mirror of https://github.com/PCSX2/pcsx2.git
Common: reformat (#4720)
* common: format AlignedMalloc.cpp * common: format AppTrait.h * common: format Assertions.h * common: format CheckedStaticBox * common: format Console * common: format Dependencies.h * common: format EmbeddedImage * common: format EventSource * common: format Exceptions * common: format FastFormatString.cpp * common: format General.h * common: format InitInterface * common: format MathUtils.h * common: format MemsetFast/MemcpyFast * common: format Mutex.cpp * common: format PageFaultSource.h * common: format Path.h * common: format PathUtils.cpp * common: format Pcsx2Types.h * common: format Perf * common: format PersistentThread.h * common: format RwMutex * common: format SafeArray * common: format ScopedAlloc.h * common: format ScopedPtrMT.h * common: format Semaphore.cpp * common: format StringHelpers * common: format ThreadTools.cpp * common: format Threading.h * common: format ThreadingDialogs * common: format ThreadingInternal.h * common: format TraceLog.h * common: format VirtualMemory.cpp * common: format pxCheckBox * common: format pxEvents.h * common: format pxForwardDefs.h * common: format pxRadioPanel * common: format pxStaticText * common: format pxStreams * common: format pxTranslate.cpp * common: format pxWindowTextWriter.cpp * common: format wxAppWithHelpers * common: format wxBaseTools.h * common: format wxGuiTools * common: format wxHelpers.cpp * common: format Darwin directory * common: format Linux directory * common: format Windows directory * common: format LnxCpuDetect.cpp * common: format WinCpuDetect.cpp * common: format bmi.cpp * common: format cpudetect.cpp * common: format cpu_detect_internal.h * common: format fpu.cpp * common: format groups.cpp * common: format instructions.h * common: format internal.h * common: format jmp.cpp * common: format legacy.cpp * common: format legacy_instructions.h * common: format legacy_internal.h * common: format movs.cpp * common: format simd.cpp * common: format tools.h * common: format x86emitter.cpp * common: format x86types.h * common: format bmi.h * common: format dwshift.h * common: format group1.h group2.h group3.h * common: format incdec.h * common: format jmpcall.h * common: format movs.h * common: format simd_arithmetic.h * common: format simd_comparisons.h * common: format simd_helpers.h * common: format simd_moremovs.h * common: format simd_shufflepack.h * common: format simd_templated_helpers.h * common: format test.h
This commit is contained in:
parent
f9bf87f50d
commit
13dfceff48
|
@ -21,33 +21,34 @@
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
#include "common/ScopedAlloc.h"
|
#include "common/ScopedAlloc.h"
|
||||||
|
|
||||||
void *__fastcall _aligned_malloc(size_t size, size_t align)
|
void* __fastcall _aligned_malloc(size_t size, size_t align)
|
||||||
{
|
{
|
||||||
pxAssert(align < 0x10000);
|
pxAssert(align < 0x10000);
|
||||||
#if defined(__USE_ISOC11) && !defined(ASAN_WORKAROUND) // not supported yet on gcc 4.9
|
#if defined(__USE_ISOC11) && !defined(ASAN_WORKAROUND) // not supported yet on gcc 4.9
|
||||||
return aligned_alloc(align, size);
|
return aligned_alloc(align, size);
|
||||||
#else
|
#else
|
||||||
void *result = 0;
|
void* result = 0;
|
||||||
posix_memalign(&result, align, size);
|
posix_memalign(&result, align, size);
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size)
|
void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size)
|
||||||
{
|
{
|
||||||
pxAssert(align < 0x10000);
|
pxAssert(align < 0x10000);
|
||||||
|
|
||||||
void *newbuf = _aligned_malloc(new_size, align);
|
void* newbuf = _aligned_malloc(new_size, align);
|
||||||
|
|
||||||
if (newbuf != NULL && handle != NULL) {
|
if (newbuf != NULL && handle != NULL)
|
||||||
memcpy(newbuf, handle, std::min(old_size, new_size));
|
{
|
||||||
_aligned_free(handle);
|
memcpy(newbuf, handle, std::min(old_size, new_size));
|
||||||
}
|
_aligned_free(handle);
|
||||||
return newbuf;
|
}
|
||||||
|
return newbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void _aligned_free(void *pmem)
|
__fi void _aligned_free(void* pmem)
|
||||||
{
|
{
|
||||||
free(pmem);
|
free(pmem);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,13 +27,13 @@
|
||||||
//
|
//
|
||||||
class Pcsx2AppTraits : public wxGUIAppTraits
|
class Pcsx2AppTraits : public wxGUIAppTraits
|
||||||
{
|
{
|
||||||
typedef wxGUIAppTraits _parent;
|
typedef wxGUIAppTraits _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Pcsx2AppTraits() {}
|
virtual ~Pcsx2AppTraits() {}
|
||||||
wxMessageOutput *CreateMessageOutput();
|
wxMessageOutput* CreateMessageOutput();
|
||||||
|
|
||||||
#ifdef wxUSE_STDPATHS
|
#ifdef wxUSE_STDPATHS
|
||||||
wxStandardPaths &GetStandardPaths();
|
wxStandardPaths& GetStandardPaths();
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef wxNullChar
|
#ifndef wxNullChar
|
||||||
#define wxNullChar ((wxChar *)NULL)
|
#define wxNullChar ((wxChar*)NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// FnChar_t - function name char type; typedef'd in case it ever changes between compilers
|
// FnChar_t - function name char type; typedef'd in case it ever changes between compilers
|
||||||
|
@ -39,29 +39,29 @@ typedef char FnChar_t;
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct DiagnosticOrigin
|
struct DiagnosticOrigin
|
||||||
{
|
{
|
||||||
const wxChar *srcfile;
|
const wxChar* srcfile;
|
||||||
const FnChar_t *function;
|
const FnChar_t* function;
|
||||||
const wxChar *condition;
|
const wxChar* condition;
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
DiagnosticOrigin(const wxChar *_file, int _line, const FnChar_t *_func, const wxChar *_cond = NULL)
|
DiagnosticOrigin(const wxChar* _file, int _line, const FnChar_t* _func, const wxChar* _cond = NULL)
|
||||||
: srcfile(_file)
|
: srcfile(_file)
|
||||||
, function(_func)
|
, function(_func)
|
||||||
, condition(_cond)
|
, condition(_cond)
|
||||||
, line(_line)
|
, line(_line)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString ToString(const wxChar *msg = NULL) const;
|
wxString ToString(const wxChar* msg = NULL) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns ture if the assertion is to trap into the debugger, or false if execution
|
// Returns ture if the assertion is to trap into the debugger, or false if execution
|
||||||
// of the program should continue unimpeded.
|
// of the program should continue unimpeded.
|
||||||
typedef bool pxDoAssertFnType(const DiagnosticOrigin &origin, const wxChar *msg);
|
typedef bool pxDoAssertFnType(const DiagnosticOrigin& origin, const wxChar* msg);
|
||||||
|
|
||||||
extern pxDoAssertFnType pxAssertImpl_LogIt;
|
extern pxDoAssertFnType pxAssertImpl_LogIt;
|
||||||
|
|
||||||
extern pxDoAssertFnType *pxDoAssert;
|
extern pxDoAssertFnType* pxDoAssert;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
// pxAssert / pxAssertDev
|
// pxAssert / pxAssertDev
|
||||||
|
@ -159,11 +159,14 @@ extern pxDoAssertFnType *pxDoAssert;
|
||||||
#define pxAssumeDev(cond, msg) (__assume(cond))
|
#define pxAssumeDev(cond, msg) (__assume(cond))
|
||||||
|
|
||||||
#define pxFail(msg) \
|
#define pxFail(msg) \
|
||||||
do { \
|
do \
|
||||||
} while (0)
|
{ \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define pxFailDev(msg) \
|
#define pxFailDev(msg) \
|
||||||
do { \
|
do \
|
||||||
} while (0)
|
{ \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -177,18 +180,18 @@ extern pxDoAssertFnType *pxDoAssert;
|
||||||
// IndexBoundsCheckDev.
|
// IndexBoundsCheckDev.
|
||||||
|
|
||||||
#define IndexBoundsCheck(objname, idx, sze) pxAssertMsg((uint)(idx) < (uint)(sze), \
|
#define IndexBoundsCheck(objname, idx, sze) pxAssertMsg((uint)(idx) < (uint)(sze), \
|
||||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||||
|
|
||||||
#define IndexBoundsCheckDev(objname, idx, sze) pxAssertDev((uint)(idx) < (uint)(sze), \
|
#define IndexBoundsCheckDev(objname, idx, sze) pxAssertDev((uint)(idx) < (uint)(sze), \
|
||||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||||
|
|
||||||
#define IndexBoundsAssume(objname, idx, sze) pxAssumeMsg((uint)(idx) < (uint)(sze), \
|
#define IndexBoundsAssume(objname, idx, sze) pxAssumeMsg((uint)(idx) < (uint)(sze), \
|
||||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||||
|
|
||||||
#define IndexBoundsAssumeDev(objname, idx, sze) pxAssumeDev((uint)(idx) < (uint)(sze), \
|
#define IndexBoundsAssumeDev(objname, idx, sze) pxAssumeDev((uint)(idx) < (uint)(sze), \
|
||||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||||
|
|
||||||
extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
|
extern void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
|
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
|
||||||
|
@ -201,9 +204,10 @@ extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
|
||||||
// * In debug/devel builds the default case will cause an assertion.
|
// * In debug/devel builds the default case will cause an assertion.
|
||||||
//
|
//
|
||||||
#ifndef jNO_DEFAULT
|
#ifndef jNO_DEFAULT
|
||||||
#define jNO_DEFAULT \
|
#define jNO_DEFAULT \
|
||||||
default: { \
|
default: \
|
||||||
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
{ \
|
||||||
break; \
|
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
||||||
}
|
break; \
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,62 +15,64 @@
|
||||||
|
|
||||||
#include "common/CheckedStaticBox.h"
|
#include "common/CheckedStaticBox.h"
|
||||||
|
|
||||||
CheckedStaticBox::CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title)
|
CheckedStaticBox::CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title)
|
||||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||||
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
|
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
|
||||||
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
|
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
|
||||||
{
|
{
|
||||||
*this += ThisToggle;
|
*this += ThisToggle;
|
||||||
*this += ThisSizer | pxExpand;
|
*this += ThisSizer | pxExpand;
|
||||||
|
|
||||||
// Ensure that the right-side of the static group box isn't too cozy:
|
// Ensure that the right-side of the static group box isn't too cozy:
|
||||||
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
|
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
|
||||||
|
|
||||||
Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId());
|
Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event handler for click events for the main checkbox (default behavior: enables/disables all child controls)
|
// Event handler for click events for the main checkbox (default behavior: enables/disables all child controls)
|
||||||
// This function can be overridden to implement custom handling of check enable/disable behavior.
|
// This function can be overridden to implement custom handling of check enable/disable behavior.
|
||||||
void CheckedStaticBox::MainToggle_Click(wxCommandEvent &evt)
|
void CheckedStaticBox::MainToggle_Click(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
SetValue(evt.IsChecked());
|
SetValue(evt.IsChecked());
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the main checkbox status, and enables/disables all child controls
|
// Sets the main checkbox status, and enables/disables all child controls
|
||||||
// bound to the StaticBox accordingly.
|
// bound to the StaticBox accordingly.
|
||||||
void CheckedStaticBox::SetValue(bool val)
|
void CheckedStaticBox::SetValue(bool val)
|
||||||
{
|
{
|
||||||
wxWindowList &list = GetChildren();
|
wxWindowList& list = GetChildren();
|
||||||
|
|
||||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||||
wxWindow *current = *iter;
|
{
|
||||||
if (current != &ThisToggle)
|
wxWindow* current = *iter;
|
||||||
current->Enable(IsEnabled() && val);
|
if (current != &ThisToggle)
|
||||||
}
|
current->Enable(IsEnabled() && val);
|
||||||
ThisToggle.SetValue(val);
|
}
|
||||||
|
ThisToggle.SetValue(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckedStaticBox::GetValue() const
|
bool CheckedStaticBox::GetValue() const
|
||||||
{
|
{
|
||||||
return ThisToggle.GetValue();
|
return ThisToggle.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This override is here so to only enable the children if both the main toggle and
|
// This override is here so to only enable the children if both the main toggle and
|
||||||
// the enable request are true. If not, disable them!
|
// the enable request are true. If not, disable them!
|
||||||
bool CheckedStaticBox::Enable(bool enable)
|
bool CheckedStaticBox::Enable(bool enable)
|
||||||
{
|
{
|
||||||
if (!_parent::Enable(enable))
|
if (!_parent::Enable(enable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool val = enable && ThisToggle.GetValue();
|
bool val = enable && ThisToggle.GetValue();
|
||||||
wxWindowList &list = GetChildren();
|
wxWindowList& list = GetChildren();
|
||||||
|
|
||||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||||
wxWindow *current = *iter;
|
{
|
||||||
if (current != &ThisToggle)
|
wxWindow* current = *iter;
|
||||||
current->Enable(val);
|
if (current != &ThisToggle)
|
||||||
}
|
current->Enable(val);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,19 +19,19 @@
|
||||||
|
|
||||||
class CheckedStaticBox : public wxPanelWithHelpers
|
class CheckedStaticBox : public wxPanelWithHelpers
|
||||||
{
|
{
|
||||||
typedef wxPanelWithHelpers _parent;
|
typedef wxPanelWithHelpers _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxBoxSizer &ThisSizer; // Boxsizer which holds all child items.
|
wxBoxSizer& ThisSizer; // Boxsizer which holds all child items.
|
||||||
wxCheckBox &ThisToggle; // toggle which can enable/disable all child controls
|
wxCheckBox& ThisToggle; // toggle which can enable/disable all child controls
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title = wxEmptyString);
|
CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title = wxEmptyString);
|
||||||
|
|
||||||
void SetValue(bool val);
|
void SetValue(bool val);
|
||||||
bool GetValue() const;
|
bool GetValue() const;
|
||||||
bool Enable(bool enable = true);
|
bool Enable(bool enable = true);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void MainToggle_Click(wxCommandEvent &evt);
|
virtual void MainToggle_Click(wxCommandEvent& evt);
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,11 +26,11 @@ static DeclareTls(int) conlog_Indent(0);
|
||||||
static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor);
|
static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor);
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
static FILE *stdout_fp = stdout;
|
static FILE* stdout_fp = stdout;
|
||||||
|
|
||||||
void Console_SetStdout(FILE *fp)
|
void Console_SetStdout(FILE* fp)
|
||||||
{
|
{
|
||||||
stdout_fp = fp;
|
stdout_fp = fp;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -41,33 +41,33 @@ void Console_SetStdout(FILE *fp)
|
||||||
// Important! Only Assert and Null console loggers are allowed during C++ startup init (when
|
// Important! Only Assert and Null console loggers are allowed during C++ startup init (when
|
||||||
// the program or DLL first loads). Other log targets rely on the static buffer and a
|
// the program or DLL first loads). Other log targets rely on the static buffer and a
|
||||||
// threaded mutex lock, which are only valid after C++ initialization has finished.
|
// threaded mutex lock, which are only valid after C++ initialization has finished.
|
||||||
void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp)
|
void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp)
|
||||||
{
|
{
|
||||||
pxAssertDev(
|
pxAssertDev(
|
||||||
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
|
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
|
||||||
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
|
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
|
||||||
(writer.DoSetColor != NULL),
|
(writer.DoSetColor != NULL),
|
||||||
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
|
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
|
||||||
|
|
||||||
Console = writer;
|
Console = writer;
|
||||||
DevConWriter = writer;
|
DevConWriter = writer;
|
||||||
|
|
||||||
#ifdef PCSX2_DEBUG
|
#ifdef PCSX2_DEBUG
|
||||||
DbgCon = writer;
|
DbgCon = writer;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes text to the Visual Studio Output window (Microsoft Windows only).
|
// Writes text to the Visual Studio Output window (Microsoft Windows only).
|
||||||
// On all other platforms this pipes to Stdout instead.
|
// On all other platforms this pipes to Stdout instead.
|
||||||
void MSW_OutputDebugString(const wxString &text)
|
void MSW_OutputDebugString(const wxString& text)
|
||||||
{
|
{
|
||||||
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
||||||
static bool hasDebugger = wxIsDebuggerRunning();
|
static bool hasDebugger = wxIsDebuggerRunning();
|
||||||
if (hasDebugger)
|
if (hasDebugger)
|
||||||
OutputDebugString(text);
|
OutputDebugString(text);
|
||||||
#else
|
#else
|
||||||
fputs(text.utf8_str(), stdout_fp);
|
fputs(text.utf8_str(), stdout_fp);
|
||||||
fflush(stdout_fp);
|
fflush(stdout_fp);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,23 +76,23 @@ void MSW_OutputDebugString(const wxString &text)
|
||||||
// ConsoleNull
|
// ConsoleNull
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void __concall ConsoleNull_SetTitle(const wxString &title) {}
|
static void __concall ConsoleNull_SetTitle(const wxString& title) {}
|
||||||
static void __concall ConsoleNull_DoSetColor(ConsoleColors color) {}
|
static void __concall ConsoleNull_DoSetColor(ConsoleColors color) {}
|
||||||
static void __concall ConsoleNull_Newline() {}
|
static void __concall ConsoleNull_Newline() {}
|
||||||
static void __concall ConsoleNull_DoWrite(const wxString &fmt) {}
|
static void __concall ConsoleNull_DoWrite(const wxString& fmt) {}
|
||||||
static void __concall ConsoleNull_DoWriteLn(const wxString &fmt) {}
|
static void __concall ConsoleNull_DoWriteLn(const wxString& fmt) {}
|
||||||
|
|
||||||
const IConsoleWriter ConsoleWriter_Null =
|
const IConsoleWriter ConsoleWriter_Null =
|
||||||
{
|
{
|
||||||
ConsoleNull_DoWrite,
|
ConsoleNull_DoWrite,
|
||||||
ConsoleNull_DoWriteLn,
|
ConsoleNull_DoWriteLn,
|
||||||
ConsoleNull_DoSetColor,
|
ConsoleNull_DoSetColor,
|
||||||
|
|
||||||
ConsoleNull_DoWrite,
|
ConsoleNull_DoWrite,
|
||||||
ConsoleNull_Newline,
|
ConsoleNull_Newline,
|
||||||
ConsoleNull_SetTitle,
|
ConsoleNull_SetTitle,
|
||||||
|
|
||||||
0, // instance-level indentation (should always be 0)
|
0, // instance-level indentation (should always be 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -100,133 +100,134 @@ const IConsoleWriter ConsoleWriter_Null =
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__unix__)
|
#if defined(__unix__)
|
||||||
static __fi const char *GetLinuxConsoleColor(ConsoleColors color)
|
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
|
||||||
{
|
{
|
||||||
switch (color) {
|
switch (color)
|
||||||
case Color_Black:
|
{
|
||||||
case Color_StrongBlack:
|
case Color_Black:
|
||||||
return "\033[30m\033[1m";
|
case Color_StrongBlack:
|
||||||
|
return "\033[30m\033[1m";
|
||||||
|
|
||||||
case Color_Red:
|
case Color_Red:
|
||||||
return "\033[31m";
|
return "\033[31m";
|
||||||
case Color_StrongRed:
|
case Color_StrongRed:
|
||||||
return "\033[31m\033[1m";
|
return "\033[31m\033[1m";
|
||||||
|
|
||||||
case Color_Green:
|
case Color_Green:
|
||||||
return "\033[32m";
|
return "\033[32m";
|
||||||
case Color_StrongGreen:
|
case Color_StrongGreen:
|
||||||
return "\033[32m\033[1m";
|
return "\033[32m\033[1m";
|
||||||
|
|
||||||
case Color_Yellow:
|
case Color_Yellow:
|
||||||
return "\033[33m";
|
return "\033[33m";
|
||||||
case Color_StrongYellow:
|
case Color_StrongYellow:
|
||||||
return "\033[33m\033[1m";
|
return "\033[33m\033[1m";
|
||||||
|
|
||||||
case Color_Blue:
|
case Color_Blue:
|
||||||
return "\033[34m";
|
return "\033[34m";
|
||||||
case Color_StrongBlue:
|
case Color_StrongBlue:
|
||||||
return "\033[34m\033[1m";
|
return "\033[34m\033[1m";
|
||||||
|
|
||||||
// No orange, so use magenta.
|
// No orange, so use magenta.
|
||||||
case Color_Orange:
|
case Color_Orange:
|
||||||
case Color_Magenta:
|
case Color_Magenta:
|
||||||
return "\033[35m";
|
return "\033[35m";
|
||||||
case Color_StrongOrange:
|
case Color_StrongOrange:
|
||||||
case Color_StrongMagenta:
|
case Color_StrongMagenta:
|
||||||
return "\033[35m\033[1m";
|
return "\033[35m\033[1m";
|
||||||
|
|
||||||
case Color_Cyan:
|
case Color_Cyan:
|
||||||
return "\033[36m";
|
return "\033[36m";
|
||||||
case Color_StrongCyan:
|
case Color_StrongCyan:
|
||||||
return "\033[36m\033[1m";
|
return "\033[36m\033[1m";
|
||||||
|
|
||||||
// Use 'white' instead of grey.
|
// Use 'white' instead of grey.
|
||||||
case Color_Gray:
|
case Color_Gray:
|
||||||
case Color_White:
|
case Color_White:
|
||||||
return "\033[37m";
|
return "\033[37m";
|
||||||
case Color_StrongGray:
|
case Color_StrongGray:
|
||||||
case Color_StrongWhite:
|
case Color_StrongWhite:
|
||||||
return "\033[37m\033[1m";
|
return "\033[37m\033[1m";
|
||||||
|
|
||||||
// On some other value being passed, clear any formatting.
|
// On some other value being passed, clear any formatting.
|
||||||
case Color_Default:
|
case Color_Default:
|
||||||
default:
|
default:
|
||||||
return "\033[0m";
|
return "\033[0m";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// One possible default write action at startup and shutdown is to use the stdout.
|
// One possible default write action at startup and shutdown is to use the stdout.
|
||||||
static void __concall ConsoleStdout_DoWrite(const wxString &fmt)
|
static void __concall ConsoleStdout_DoWrite(const wxString& fmt)
|
||||||
{
|
{
|
||||||
MSW_OutputDebugString(fmt);
|
MSW_OutputDebugString(fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default write action at startup and shutdown is to use the stdout.
|
// Default write action at startup and shutdown is to use the stdout.
|
||||||
static void __concall ConsoleStdout_DoWriteLn(const wxString &fmt)
|
static void __concall ConsoleStdout_DoWriteLn(const wxString& fmt)
|
||||||
{
|
{
|
||||||
MSW_OutputDebugString(fmt + L"\n");
|
MSW_OutputDebugString(fmt + L"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __concall ConsoleStdout_Newline()
|
static void __concall ConsoleStdout_Newline()
|
||||||
{
|
{
|
||||||
MSW_OutputDebugString(L"\n");
|
MSW_OutputDebugString(L"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __concall ConsoleStdout_DoSetColor(ConsoleColors color)
|
static void __concall ConsoleStdout_DoSetColor(ConsoleColors color)
|
||||||
{
|
{
|
||||||
#if defined(__unix__)
|
#if defined(__unix__)
|
||||||
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
|
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
|
||||||
fflush(stdout_fp);
|
fflush(stdout_fp);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __concall ConsoleStdout_SetTitle(const wxString &title)
|
static void __concall ConsoleStdout_SetTitle(const wxString& title)
|
||||||
{
|
{
|
||||||
#if defined(__unix__)
|
#if defined(__unix__)
|
||||||
fputs("\033]0;", stdout_fp);
|
fputs("\033]0;", stdout_fp);
|
||||||
fputs(title.utf8_str(), stdout_fp);
|
fputs(title.utf8_str(), stdout_fp);
|
||||||
fputs("\007", stdout_fp);
|
fputs("\007", stdout_fp);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const IConsoleWriter ConsoleWriter_Stdout =
|
const IConsoleWriter ConsoleWriter_Stdout =
|
||||||
{
|
{
|
||||||
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
|
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
|
||||||
ConsoleStdout_DoWriteLn,
|
ConsoleStdout_DoWriteLn,
|
||||||
ConsoleStdout_DoSetColor,
|
ConsoleStdout_DoSetColor,
|
||||||
|
|
||||||
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
|
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
|
||||||
ConsoleStdout_Newline,
|
ConsoleStdout_Newline,
|
||||||
ConsoleStdout_SetTitle,
|
ConsoleStdout_SetTitle,
|
||||||
0, // instance-level indentation (should always be 0)
|
0, // instance-level indentation (should always be 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ConsoleAssert
|
// ConsoleAssert
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void __concall ConsoleAssert_DoWrite(const wxString &fmt)
|
static void __concall ConsoleAssert_DoWrite(const wxString& fmt)
|
||||||
{
|
{
|
||||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __concall ConsoleAssert_DoWriteLn(const wxString &fmt)
|
static void __concall ConsoleAssert_DoWriteLn(const wxString& fmt)
|
||||||
{
|
{
|
||||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IConsoleWriter ConsoleWriter_Assert =
|
const IConsoleWriter ConsoleWriter_Assert =
|
||||||
{
|
{
|
||||||
ConsoleAssert_DoWrite,
|
ConsoleAssert_DoWrite,
|
||||||
ConsoleAssert_DoWriteLn,
|
ConsoleAssert_DoWriteLn,
|
||||||
ConsoleNull_DoSetColor,
|
ConsoleNull_DoSetColor,
|
||||||
|
|
||||||
ConsoleNull_DoWrite,
|
ConsoleNull_DoWrite,
|
||||||
ConsoleNull_Newline,
|
ConsoleNull_Newline,
|
||||||
ConsoleNull_SetTitle,
|
ConsoleNull_SetTitle,
|
||||||
|
|
||||||
0, // instance-level indentation (should always be 0)
|
0, // instance-level indentation (should always be 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
@ -239,170 +240,170 @@ const IConsoleWriter ConsoleWriter_Assert =
|
||||||
// glob_indent - this parameter is used to specify a global indentation setting. It is used by
|
// glob_indent - this parameter is used to specify a global indentation setting. It is used by
|
||||||
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
|
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
|
||||||
// applies to all writes.
|
// applies to all writes.
|
||||||
wxString IConsoleWriter::_addIndentation(const wxString &src, int glob_indent = 0) const
|
wxString IConsoleWriter::_addIndentation(const wxString& src, int glob_indent = 0) const
|
||||||
{
|
{
|
||||||
const int indent = glob_indent + _imm_indentation;
|
const int indent = glob_indent + _imm_indentation;
|
||||||
if (indent == 0)
|
if (indent == 0)
|
||||||
return src;
|
return src;
|
||||||
|
|
||||||
wxString result(src);
|
wxString result(src);
|
||||||
const wxString indentStr(L'\t', indent);
|
const wxString indentStr(L'\t', indent);
|
||||||
result.Replace(L"\n", L"\n" + indentStr);
|
result.Replace(L"\n", L"\n" + indentStr);
|
||||||
return indentStr + result;
|
return indentStr + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the indentation to be applied to all WriteLn's. The indentation is added to the
|
// Sets the indentation to be applied to all WriteLn's. The indentation is added to the
|
||||||
// primary write, and to any newlines specified within the write. Note that this applies
|
// primary write, and to any newlines specified within the write. Note that this applies
|
||||||
// to calls to WriteLn *only* -- calls to Write bypass the indentation parser.
|
// to calls to WriteLn *only* -- calls to Write bypass the indentation parser.
|
||||||
const IConsoleWriter &IConsoleWriter::SetIndent(int tabcount) const
|
const IConsoleWriter& IConsoleWriter::SetIndent(int tabcount) const
|
||||||
{
|
{
|
||||||
conlog_Indent += tabcount;
|
conlog_Indent += tabcount;
|
||||||
pxAssert(conlog_Indent >= 0);
|
pxAssert(conlog_Indent >= 0);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IConsoleWriter IConsoleWriter::Indent(int tabcount) const
|
IConsoleWriter IConsoleWriter::Indent(int tabcount) const
|
||||||
{
|
{
|
||||||
IConsoleWriter retval = *this;
|
IConsoleWriter retval = *this;
|
||||||
retval._imm_indentation = tabcount;
|
retval._imm_indentation = tabcount;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes the active console color.
|
// Changes the active console color.
|
||||||
// This color will be unset by calls to colored text methods
|
// This color will be unset by calls to colored text methods
|
||||||
// such as ErrorMsg and Notice.
|
// such as ErrorMsg and Notice.
|
||||||
const IConsoleWriter &IConsoleWriter::SetColor(ConsoleColors color) const
|
const IConsoleWriter& IConsoleWriter::SetColor(ConsoleColors color) const
|
||||||
{
|
{
|
||||||
// Ignore current color requests since, well, the current color is already set. ;)
|
// Ignore current color requests since, well, the current color is already set. ;)
|
||||||
if (color == Color_Current)
|
if (color == Color_Current)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
|
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
|
||||||
|
|
||||||
if (conlog_Color != color)
|
if (conlog_Color != color)
|
||||||
DoSetColor(conlog_Color = color);
|
DoSetColor(conlog_Color = color);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleColors IConsoleWriter::GetColor() const
|
ConsoleColors IConsoleWriter::GetColor() const
|
||||||
{
|
{
|
||||||
return conlog_Color;
|
return conlog_Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restores the console color to default (usually black, or low-intensity white if the console uses a black background)
|
// Restores the console color to default (usually black, or low-intensity white if the console uses a black background)
|
||||||
const IConsoleWriter &IConsoleWriter::ClearColor() const
|
const IConsoleWriter& IConsoleWriter::ClearColor() const
|
||||||
{
|
{
|
||||||
if (conlog_Color != DefaultConsoleColor)
|
if (conlog_Color != DefaultConsoleColor)
|
||||||
DoSetColor(conlog_Color = DefaultConsoleColor);
|
DoSetColor(conlog_Color = DefaultConsoleColor);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ASCII/UTF8 (char*)
|
// ASCII/UTF8 (char*)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool IConsoleWriter::FormatV(const char *fmt, va_list args) const
|
bool IConsoleWriter::FormatV(const char* fmt, va_list args) const
|
||||||
{
|
{
|
||||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::WriteLn(const char *fmt, ...) const
|
bool IConsoleWriter::WriteLn(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const char *fmt, ...) const
|
bool IConsoleWriter::WriteLn(ConsoleColors color, const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(color);
|
ConsoleColorScope cs(color);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Error(const char *fmt, ...) const
|
bool IConsoleWriter::Error(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongRed);
|
ConsoleColorScope cs(Color_StrongRed);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Warning(const char *fmt, ...) const
|
bool IConsoleWriter::Warning(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongOrange);
|
ConsoleColorScope cs(Color_StrongOrange);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Write Variants - Unicode/UTF16 style
|
// Write Variants - Unicode/UTF16 style
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool IConsoleWriter::FormatV(const wxChar *fmt, va_list args) const
|
bool IConsoleWriter::FormatV(const wxChar* fmt, va_list args) const
|
||||||
{
|
{
|
||||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::WriteLn(const wxChar *fmt, ...) const
|
bool IConsoleWriter::WriteLn(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar *fmt, ...) const
|
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(color);
|
ConsoleColorScope cs(color);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Error(const wxChar *fmt, ...) const
|
bool IConsoleWriter::Error(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongRed);
|
ConsoleColorScope cs(Color_StrongRed);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Warning(const wxChar *fmt, ...) const
|
bool IConsoleWriter::Warning(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongOrange);
|
ConsoleColorScope cs(Color_StrongOrange);
|
||||||
FormatV(fmt, args);
|
FormatV(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -410,45 +411,45 @@ bool IConsoleWriter::Warning(const wxChar *fmt, ...) const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
bool IConsoleWriter::WriteLn(const wxString fmt, ...) const
|
bool IConsoleWriter::WriteLn(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
FormatV(fmt.wx_str(), args);
|
FormatV(fmt.wx_str(), args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const
|
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(color);
|
ConsoleColorScope cs(color);
|
||||||
FormatV(fmt.wx_str(), args);
|
FormatV(fmt.wx_str(), args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Error(const wxString fmt, ...) const
|
bool IConsoleWriter::Error(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongRed);
|
ConsoleColorScope cs(Color_StrongRed);
|
||||||
FormatV(fmt.wx_str(), args);
|
FormatV(fmt.wx_str(), args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IConsoleWriter::Warning(const wxString fmt, ...) const
|
bool IConsoleWriter::Warning(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
ConsoleColorScope cs(Color_StrongOrange);
|
ConsoleColorScope cs(Color_StrongOrange);
|
||||||
FormatV(fmt.wx_str(), args);
|
FormatV(fmt.wx_str(), args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -458,70 +459,73 @@ bool IConsoleWriter::Warning(const wxString fmt, ...) const
|
||||||
|
|
||||||
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
|
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
|
||||||
{
|
{
|
||||||
m_IsScoped = false;
|
m_IsScoped = false;
|
||||||
m_newcolor = newcolor;
|
m_newcolor = newcolor;
|
||||||
EnterScope();
|
EnterScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleColorScope::~ConsoleColorScope()
|
ConsoleColorScope::~ConsoleColorScope()
|
||||||
{
|
{
|
||||||
LeaveScope();
|
LeaveScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleColorScope::EnterScope()
|
void ConsoleColorScope::EnterScope()
|
||||||
{
|
{
|
||||||
if (!m_IsScoped) {
|
if (!m_IsScoped)
|
||||||
m_old_color = Console.GetColor();
|
{
|
||||||
Console.SetColor(m_newcolor);
|
m_old_color = Console.GetColor();
|
||||||
m_IsScoped = true;
|
Console.SetColor(m_newcolor);
|
||||||
}
|
m_IsScoped = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleColorScope::LeaveScope()
|
void ConsoleColorScope::LeaveScope()
|
||||||
{
|
{
|
||||||
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
|
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleIndentScope::ConsoleIndentScope(int tabs)
|
ConsoleIndentScope::ConsoleIndentScope(int tabs)
|
||||||
{
|
{
|
||||||
m_IsScoped = false;
|
m_IsScoped = false;
|
||||||
m_amount = tabs;
|
m_amount = tabs;
|
||||||
EnterScope();
|
EnterScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleIndentScope::~ConsoleIndentScope()
|
ConsoleIndentScope::~ConsoleIndentScope()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
LeaveScope();
|
{
|
||||||
}
|
LeaveScope();
|
||||||
DESTRUCTOR_CATCHALL
|
}
|
||||||
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleIndentScope::EnterScope()
|
void ConsoleIndentScope::EnterScope()
|
||||||
{
|
{
|
||||||
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
|
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleIndentScope::LeaveScope()
|
void ConsoleIndentScope::LeaveScope()
|
||||||
{
|
{
|
||||||
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
|
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
|
ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
|
||||||
{
|
{
|
||||||
m_old_color = Console.GetColor();
|
m_old_color = Console.GetColor();
|
||||||
Console.SetIndent(m_tabsize = indent);
|
Console.SetIndent(m_tabsize = indent);
|
||||||
Console.SetColor(newcolor);
|
Console.SetColor(newcolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleAttrScope::~ConsoleAttrScope()
|
ConsoleAttrScope::~ConsoleAttrScope()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
Console.SetColor(m_old_color);
|
{
|
||||||
Console.SetIndent(-m_tabsize);
|
Console.SetColor(m_old_color);
|
||||||
}
|
Console.SetIndent(-m_tabsize);
|
||||||
DESTRUCTOR_CATCHALL
|
}
|
||||||
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -552,31 +556,31 @@ NullConsoleWriter NullCon = {};
|
||||||
|
|
||||||
// Writes to the console using the specified color. This overrides the default color setting
|
// Writes to the console using the specified color. This overrides the default color setting
|
||||||
// for this log.
|
// for this log.
|
||||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const char *fmt, va_list list) const
|
bool ConsoleLogSource::WriteV(ConsoleColors color, const char* fmt, va_list list) const
|
||||||
{
|
{
|
||||||
ConsoleColorScope cs(color);
|
ConsoleColorScope cs(color);
|
||||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const
|
bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const
|
||||||
{
|
{
|
||||||
ConsoleColorScope cs(color);
|
ConsoleColorScope cs(color);
|
||||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes to the console using the source's default color. Note that the source's default
|
// Writes to the console using the source's default color. Note that the source's default
|
||||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||||
// console's default color is Color_Default.
|
// console's default color is Color_Default.
|
||||||
bool ConsoleLogSource::WriteV(const char *fmt, va_list list) const
|
bool ConsoleLogSource::WriteV(const char* fmt, va_list list) const
|
||||||
{
|
{
|
||||||
WriteV(DefaultColor, fmt, list);
|
WriteV(DefaultColor, fmt, list);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleLogSource::WriteV(const wxChar *fmt, va_list list) const
|
bool ConsoleLogSource::WriteV(const wxChar* fmt, va_list list) const
|
||||||
{
|
{
|
||||||
WriteV(DefaultColor, fmt, list);
|
WriteV(DefaultColor, fmt, list);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
239
common/Console.h
239
common/Console.h
|
@ -15,40 +15,41 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "StringHelpers.h"
|
#include "common/StringHelpers.h"
|
||||||
|
|
||||||
enum ConsoleColors {
|
enum ConsoleColors
|
||||||
Color_Current = -1,
|
{
|
||||||
|
Color_Current = -1,
|
||||||
|
|
||||||
Color_Default = 0,
|
Color_Default = 0,
|
||||||
|
|
||||||
Color_Black,
|
Color_Black,
|
||||||
Color_Green,
|
Color_Green,
|
||||||
Color_Red,
|
Color_Red,
|
||||||
Color_Blue,
|
Color_Blue,
|
||||||
Color_Magenta,
|
Color_Magenta,
|
||||||
Color_Orange,
|
Color_Orange,
|
||||||
Color_Gray,
|
Color_Gray,
|
||||||
|
|
||||||
Color_Cyan, // faint visibility, intended for logging PS2/IOP output
|
Color_Cyan, // faint visibility, intended for logging PS2/IOP output
|
||||||
Color_Yellow, // faint visibility, intended for logging PS2/IOP output
|
Color_Yellow, // faint visibility, intended for logging PS2/IOP output
|
||||||
Color_White, // faint visibility, intended for logging PS2/IOP output
|
Color_White, // faint visibility, intended for logging PS2/IOP output
|
||||||
|
|
||||||
// Strong text *may* result in mis-aligned text in the console, depending on the
|
// Strong text *may* result in mis-aligned text in the console, depending on the
|
||||||
// font and the platform, so use these with caution.
|
// font and the platform, so use these with caution.
|
||||||
Color_StrongBlack,
|
Color_StrongBlack,
|
||||||
Color_StrongRed, // intended for errors
|
Color_StrongRed, // intended for errors
|
||||||
Color_StrongGreen, // intended for infrequent state information
|
Color_StrongGreen, // intended for infrequent state information
|
||||||
Color_StrongBlue, // intended for block headings
|
Color_StrongBlue, // intended for block headings
|
||||||
Color_StrongMagenta,
|
Color_StrongMagenta,
|
||||||
Color_StrongOrange, // intended for warnings
|
Color_StrongOrange, // intended for warnings
|
||||||
Color_StrongGray,
|
Color_StrongGray,
|
||||||
|
|
||||||
Color_StrongCyan,
|
Color_StrongCyan,
|
||||||
Color_StrongYellow,
|
Color_StrongYellow,
|
||||||
Color_StrongWhite,
|
Color_StrongWhite,
|
||||||
|
|
||||||
ConsoleColors_Count
|
ConsoleColors_Count
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ConsoleColors DefaultConsoleColor = Color_Default;
|
static const ConsoleColors DefaultConsoleColor = Color_Default;
|
||||||
|
@ -70,60 +71,60 @@ static const ConsoleColors DefaultConsoleColor = Color_Default;
|
||||||
//
|
//
|
||||||
struct IConsoleWriter
|
struct IConsoleWriter
|
||||||
{
|
{
|
||||||
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick
|
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick
|
||||||
// logging of various junk; but should *not* be used in production code due.
|
// logging of various junk; but should *not* be used in production code due.
|
||||||
void(__concall *WriteRaw)(const wxString &fmt);
|
void(__concall* WriteRaw)(const wxString& fmt);
|
||||||
|
|
||||||
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
|
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
|
||||||
// formatting.
|
// formatting.
|
||||||
void(__concall *DoWriteLn)(const wxString &fmt);
|
void(__concall* DoWriteLn)(const wxString& fmt);
|
||||||
|
|
||||||
// SetColor implementation for internal use only.
|
// SetColor implementation for internal use only.
|
||||||
void(__concall *DoSetColor)(ConsoleColors color);
|
void(__concall* DoSetColor)(ConsoleColors color);
|
||||||
|
|
||||||
// Special implementation of DoWrite that's pretty much for MSVC use only.
|
// Special implementation of DoWrite that's pretty much for MSVC use only.
|
||||||
// All implementations should map to DoWrite, except Stdio which should map to Null.
|
// All implementations should map to DoWrite, except Stdio which should map to Null.
|
||||||
// (This avoids circular/recursive stdio output)
|
// (This avoids circular/recursive stdio output)
|
||||||
void(__concall *DoWriteFromStdout)(const wxString &fmt);
|
void(__concall* DoWriteFromStdout)(const wxString& fmt);
|
||||||
|
|
||||||
void(__concall *Newline)();
|
void(__concall* Newline)();
|
||||||
void(__concall *SetTitle)(const wxString &title);
|
void(__concall* SetTitle)(const wxString& title);
|
||||||
|
|
||||||
// internal value for indentation of individual lines. Use the Indent() member to invoke.
|
// internal value for indentation of individual lines. Use the Indent() member to invoke.
|
||||||
int _imm_indentation;
|
int _imm_indentation;
|
||||||
|
|
||||||
// For internal use only.
|
// For internal use only.
|
||||||
wxString _addIndentation(const wxString &src, int glob_indent) const;
|
wxString _addIndentation(const wxString& src, int glob_indent) const;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Public members; call these to print stuff to console!
|
// Public members; call these to print stuff to console!
|
||||||
//
|
//
|
||||||
// All functions always return false. Return value is provided only so that we can easily
|
// All functions always return false. Return value is provided only so that we can easily
|
||||||
// disable logs at compile time using the "0&&action" macro trick.
|
// disable logs at compile time using the "0&&action" macro trick.
|
||||||
|
|
||||||
ConsoleColors GetColor() const;
|
ConsoleColors GetColor() const;
|
||||||
const IConsoleWriter &SetColor(ConsoleColors color) const;
|
const IConsoleWriter& SetColor(ConsoleColors color) const;
|
||||||
const IConsoleWriter &ClearColor() const;
|
const IConsoleWriter& ClearColor() const;
|
||||||
const IConsoleWriter &SetIndent(int tabcount = 1) const;
|
const IConsoleWriter& SetIndent(int tabcount = 1) const;
|
||||||
|
|
||||||
IConsoleWriter Indent(int tabcount = 1) const;
|
IConsoleWriter Indent(int tabcount = 1) const;
|
||||||
|
|
||||||
bool FormatV(const char *fmt, va_list args) const;
|
bool FormatV(const char* fmt, va_list args) const;
|
||||||
bool WriteLn(ConsoleColors color, const char *fmt, ...) const;
|
bool WriteLn(ConsoleColors color, const char* fmt, ...) const;
|
||||||
bool WriteLn(const char *fmt, ...) const;
|
bool WriteLn(const char* fmt, ...) const;
|
||||||
bool Error(const char *fmt, ...) const;
|
bool Error(const char* fmt, ...) const;
|
||||||
bool Warning(const char *fmt, ...) const;
|
bool Warning(const char* fmt, ...) const;
|
||||||
|
|
||||||
bool FormatV(const wxChar *fmt, va_list args) const;
|
bool FormatV(const wxChar* fmt, va_list args) const;
|
||||||
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const;
|
bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const;
|
||||||
bool WriteLn(const wxChar *fmt, ...) const;
|
bool WriteLn(const wxChar* fmt, ...) const;
|
||||||
bool Error(const wxChar *fmt, ...) const;
|
bool Error(const wxChar* fmt, ...) const;
|
||||||
bool Warning(const wxChar *fmt, ...) const;
|
bool Warning(const wxChar* fmt, ...) const;
|
||||||
|
|
||||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
|
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
|
||||||
bool WriteLn(const wxString fmt, ...) const;
|
bool WriteLn(const wxString fmt, ...) const;
|
||||||
bool Error(const wxString fmt, ...) const;
|
bool Error(const wxString fmt, ...) const;
|
||||||
bool Warning(const wxString fmt, ...) const;
|
bool Warning(const wxString fmt, ...) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -133,37 +134,37 @@ struct IConsoleWriter
|
||||||
//
|
//
|
||||||
struct NullConsoleWriter
|
struct NullConsoleWriter
|
||||||
{
|
{
|
||||||
void WriteRaw(const wxString &fmt) {}
|
void WriteRaw(const wxString& fmt) {}
|
||||||
void DoWriteLn(const wxString &fmt) {}
|
void DoWriteLn(const wxString& fmt) {}
|
||||||
void DoSetColor(ConsoleColors color) {}
|
void DoSetColor(ConsoleColors color) {}
|
||||||
void DoWriteFromStdout(const wxString &fmt) {}
|
void DoWriteFromStdout(const wxString& fmt) {}
|
||||||
void Newline() {}
|
void Newline() {}
|
||||||
void SetTitle(const wxString &title) {}
|
void SetTitle(const wxString& title) {}
|
||||||
|
|
||||||
|
|
||||||
ConsoleColors GetColor() const { return Color_Current; }
|
ConsoleColors GetColor() const { return Color_Current; }
|
||||||
const NullConsoleWriter &SetColor(ConsoleColors color) const { return *this; }
|
const NullConsoleWriter& SetColor(ConsoleColors color) const { return *this; }
|
||||||
const NullConsoleWriter &ClearColor() const { return *this; }
|
const NullConsoleWriter& ClearColor() const { return *this; }
|
||||||
const NullConsoleWriter &SetIndent(int tabcount = 1) const { return *this; }
|
const NullConsoleWriter& SetIndent(int tabcount = 1) const { return *this; }
|
||||||
|
|
||||||
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
|
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
|
||||||
|
|
||||||
bool FormatV(const char *fmt, va_list args) const { return false; }
|
bool FormatV(const char* fmt, va_list args) const { return false; }
|
||||||
bool WriteLn(ConsoleColors color, const char *fmt, ...) const { return false; }
|
bool WriteLn(ConsoleColors color, const char* fmt, ...) const { return false; }
|
||||||
bool WriteLn(const char *fmt, ...) const { return false; }
|
bool WriteLn(const char* fmt, ...) const { return false; }
|
||||||
bool Error(const char *fmt, ...) const { return false; }
|
bool Error(const char* fmt, ...) const { return false; }
|
||||||
bool Warning(const char *fmt, ...) const { return false; }
|
bool Warning(const char* fmt, ...) const { return false; }
|
||||||
|
|
||||||
bool FormatV(const wxChar *fmt, va_list args) const { return false; }
|
bool FormatV(const wxChar* fmt, va_list args) const { return false; }
|
||||||
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const { return false; }
|
bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const { return false; }
|
||||||
bool WriteLn(const wxChar *fmt, ...) const { return false; }
|
bool WriteLn(const wxChar* fmt, ...) const { return false; }
|
||||||
bool Error(const wxChar *fmt, ...) const { return false; }
|
bool Error(const wxChar* fmt, ...) const { return false; }
|
||||||
bool Warning(const wxChar *fmt, ...) const { return false; }
|
bool Warning(const wxChar* fmt, ...) const { return false; }
|
||||||
|
|
||||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; }
|
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; }
|
||||||
bool WriteLn(const wxString fmt, ...) const { return false; }
|
bool WriteLn(const wxString fmt, ...) const { return false; }
|
||||||
bool Error(const wxString fmt, ...) const { return false; }
|
bool Error(const wxString fmt, ...) const { return false; }
|
||||||
bool Warning(const wxString fmt, ...) const { return false; }
|
bool Warning(const wxString fmt, ...) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -179,19 +180,19 @@ struct NullConsoleWriter
|
||||||
//
|
//
|
||||||
class ConsoleIndentScope
|
class ConsoleIndentScope
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ConsoleIndentScope);
|
DeclareNoncopyableObject(ConsoleIndentScope);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_amount;
|
int m_amount;
|
||||||
bool m_IsScoped;
|
bool m_IsScoped;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor: The specified number of tabs will be appended to the current indentation
|
// Constructor: The specified number of tabs will be appended to the current indentation
|
||||||
// setting. The tabs will be unrolled when the object leaves scope or is destroyed.
|
// setting. The tabs will be unrolled when the object leaves scope or is destroyed.
|
||||||
ConsoleIndentScope(int tabs = 1);
|
ConsoleIndentScope(int tabs = 1);
|
||||||
virtual ~ConsoleIndentScope();
|
virtual ~ConsoleIndentScope();
|
||||||
void EnterScope();
|
void EnterScope();
|
||||||
void LeaveScope();
|
void LeaveScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -199,18 +200,18 @@ public:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class ConsoleColorScope
|
class ConsoleColorScope
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ConsoleColorScope);
|
DeclareNoncopyableObject(ConsoleColorScope);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ConsoleColors m_newcolor;
|
ConsoleColors m_newcolor;
|
||||||
ConsoleColors m_old_color;
|
ConsoleColors m_old_color;
|
||||||
bool m_IsScoped;
|
bool m_IsScoped;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleColorScope(ConsoleColors newcolor);
|
ConsoleColorScope(ConsoleColors newcolor);
|
||||||
virtual ~ConsoleColorScope();
|
virtual ~ConsoleColorScope();
|
||||||
void EnterScope();
|
void EnterScope();
|
||||||
void LeaveScope();
|
void LeaveScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -220,23 +221,23 @@ public:
|
||||||
//
|
//
|
||||||
class ConsoleAttrScope
|
class ConsoleAttrScope
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ConsoleAttrScope);
|
DeclareNoncopyableObject(ConsoleAttrScope);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ConsoleColors m_old_color;
|
ConsoleColors m_old_color;
|
||||||
int m_tabsize;
|
int m_tabsize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
|
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
|
||||||
virtual ~ConsoleAttrScope();
|
virtual ~ConsoleAttrScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern IConsoleWriter Console;
|
extern IConsoleWriter Console;
|
||||||
|
|
||||||
#if defined(__unix__) || defined(__APPLE__)
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
extern void Console_SetStdout(FILE *fp);
|
extern void Console_SetStdout(FILE* fp);
|
||||||
#endif
|
#endif
|
||||||
extern void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp = NULL);
|
extern void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp = NULL);
|
||||||
|
|
||||||
extern const IConsoleWriter ConsoleWriter_Null;
|
extern const IConsoleWriter ConsoleWriter_Null;
|
||||||
extern const IConsoleWriter ConsoleWriter_Stdout;
|
extern const IConsoleWriter ConsoleWriter_Stdout;
|
||||||
|
@ -250,7 +251,7 @@ extern bool DevConWriterEnabled;
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
#define DevCon DevConWriter
|
#define DevCon DevConWriter
|
||||||
#else
|
#else
|
||||||
#define DevCon DevConWriterEnabled &&DevConWriter
|
#define DevCon DevConWriterEnabled&& DevConWriter
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PCSX2_DEBUG
|
#ifdef PCSX2_DEBUG
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "common/Pcsx2Types.h"
|
#include "common/Pcsx2Types.h"
|
||||||
|
|
||||||
#define NELEM(x) \
|
#define NELEM(x) \
|
||||||
((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
||||||
|
|
||||||
// Darwin (OSX) is a bit different from Linux when requesting properties of
|
// Darwin (OSX) is a bit different from Linux when requesting properties of
|
||||||
// the OS because of its BSD/Mach heritage. Helpfully, most of this code
|
// the OS because of its BSD/Mach heritage. Helpfully, most of this code
|
||||||
|
@ -39,23 +39,25 @@
|
||||||
// failure (not supported by the operating system).
|
// failure (not supported by the operating system).
|
||||||
u64 GetPhysicalMemory()
|
u64 GetPhysicalMemory()
|
||||||
{
|
{
|
||||||
static u64 mem = 0;
|
static u64 mem = 0;
|
||||||
|
|
||||||
// fetch the total memory only once, as its an expensive system call and
|
// fetch the total memory only once, as its an expensive system call and
|
||||||
// doesn't change during the course of the program. Thread-safety is
|
// doesn't change during the course of the program. Thread-safety is
|
||||||
// ensured by atomic operations with full-barriers (usually compiled
|
// ensured by atomic operations with full-barriers (usually compiled
|
||||||
// down to XCHG on x86).
|
// down to XCHG on x86).
|
||||||
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0)
|
||||||
u64 getmem = 0;
|
{
|
||||||
size_t len = sizeof(getmem);
|
u64 getmem = 0;
|
||||||
int mib[] = {CTL_HW, HW_MEMSIZE};
|
size_t len = sizeof(getmem);
|
||||||
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) {
|
int mib[] = {CTL_HW, HW_MEMSIZE};
|
||||||
perror("sysctl:");
|
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0)
|
||||||
}
|
{
|
||||||
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
perror("sysctl:");
|
||||||
}
|
}
|
||||||
|
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitCPUTicks()
|
void InitCPUTicks()
|
||||||
|
@ -72,26 +74,28 @@ void InitCPUTicks()
|
||||||
// GetTickFrequency() to maintain good precision.
|
// GetTickFrequency() to maintain good precision.
|
||||||
u64 GetTickFrequency()
|
u64 GetTickFrequency()
|
||||||
{
|
{
|
||||||
static u64 freq = 0;
|
static u64 freq = 0;
|
||||||
|
|
||||||
// by the time denom is not 0, the structure will have been fully
|
// by the time denom is not 0, the structure will have been fully
|
||||||
// updated and no more atomic accesses are necessary.
|
// updated and no more atomic accesses are necessary.
|
||||||
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0)
|
||||||
mach_timebase_info_data_t info;
|
{
|
||||||
|
mach_timebase_info_data_t info;
|
||||||
|
|
||||||
// mach_timebase_info() is a syscall, very slow, that's why we take
|
// mach_timebase_info() is a syscall, very slow, that's why we take
|
||||||
// pains to only do it once. On x86(-64), the result is guaranteed
|
// pains to only do it once. On x86(-64), the result is guaranteed
|
||||||
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
||||||
// which means GetCPUTicks is just nanoseconds).
|
// which means GetCPUTicks is just nanoseconds).
|
||||||
if (mach_timebase_info(&info) != KERN_SUCCESS) {
|
if (mach_timebase_info(&info) != KERN_SUCCESS)
|
||||||
abort();
|
{
|
||||||
}
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
// store the calculated value atomically
|
// store the calculated value atomically
|
||||||
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the number of "ticks" since some arbitrary, fixed time in the
|
// return the number of "ticks" since some arbitrary, fixed time in the
|
||||||
|
@ -100,53 +104,55 @@ u64 GetTickFrequency()
|
||||||
// nanoseconds.
|
// nanoseconds.
|
||||||
u64 GetCPUTicks()
|
u64 GetCPUTicks()
|
||||||
{
|
{
|
||||||
return mach_absolute_time();
|
return mach_absolute_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString GetOSVersionString()
|
wxString GetOSVersionString()
|
||||||
{
|
{
|
||||||
wxString version;
|
wxString version;
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
|
|
||||||
// fetch the OS description only once (thread-safely)
|
// fetch the OS description only once (thread-safely)
|
||||||
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0)
|
||||||
char type[32] = {0};
|
{
|
||||||
char release[32] = {0};
|
char type[32] = {0};
|
||||||
char arch[32] = {0};
|
char release[32] = {0};
|
||||||
|
char arch[32] = {0};
|
||||||
|
|
||||||
#define SYSCTL_GET(var, base, name) \
|
#define SYSCTL_GET(var, base, name) \
|
||||||
do { \
|
do \
|
||||||
int mib[] = {base, name}; \
|
{ \
|
||||||
size_t len = sizeof(var); \
|
int mib[] = {base, name}; \
|
||||||
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
size_t len = sizeof(var); \
|
||||||
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
|
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
||||||
} while (0)
|
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
|
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
|
||||||
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
|
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
|
||||||
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
|
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
|
||||||
|
|
||||||
#undef SYSCTL_KERN
|
#undef SYSCTL_KERN
|
||||||
|
|
||||||
// I know strcat is not good, but stpcpy is not universally
|
// I know strcat is not good, but stpcpy is not universally
|
||||||
// available yet.
|
// available yet.
|
||||||
char buf[128] = {0};
|
char buf[128] = {0};
|
||||||
strcat(buf, type);
|
strcat(buf, type);
|
||||||
strcat(buf, " ");
|
strcat(buf, " ");
|
||||||
strcat(buf, release);
|
strcat(buf, release);
|
||||||
strcat(buf, " ");
|
strcat(buf, " ");
|
||||||
strcat(buf, arch);
|
strcat(buf, arch);
|
||||||
|
|
||||||
version = buf;
|
version = buf;
|
||||||
|
|
||||||
__atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreensaverAllow(bool allow)
|
void ScreensaverAllow(bool allow)
|
||||||
{
|
{
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
#include <pthread.h> // pthread_setcancelstate()
|
#include <pthread.h> // pthread_setcancelstate()
|
||||||
#include <sys/time.h> // gettimeofday()
|
#include <sys/time.h> // gettimeofday()
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/task.h> // semaphore_create() and semaphore_destroy()
|
#include <mach/task.h> // semaphore_create() and semaphore_destroy()
|
||||||
#include <mach/semaphore.h> // semaphore_*()
|
#include <mach/semaphore.h> // semaphore_*()
|
||||||
#include <mach/mach_error.h> // mach_error_string()
|
#include <mach/mach_error.h> // mach_error_string()
|
||||||
#include <mach/mach_time.h> // mach_absolute_time()
|
#include <mach/mach_time.h> // mach_absolute_time()
|
||||||
|
|
||||||
#include "common/Threading.h"
|
#include "common/Threading.h"
|
||||||
#include "common/ThreadingInternal.h"
|
#include "common/ThreadingInternal.h"
|
||||||
|
@ -45,107 +45,113 @@
|
||||||
|
|
||||||
static void MACH_CHECK(kern_return_t mach_retval)
|
static void MACH_CHECK(kern_return_t mach_retval)
|
||||||
{
|
{
|
||||||
switch (mach_retval) {
|
switch (mach_retval)
|
||||||
case KERN_SUCCESS: break;
|
{
|
||||||
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
|
case KERN_SUCCESS:
|
||||||
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
|
break;
|
||||||
// fallthrough
|
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
|
||||||
default:
|
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
|
||||||
fprintf(stderr, "mach error: %s", mach_error_string(mach_retval));
|
// fallthrough
|
||||||
assert(mach_retval == KERN_SUCCESS);
|
default:
|
||||||
}
|
fprintf(stderr, "mach error: %s", mach_error_string(mach_retval));
|
||||||
|
assert(mach_retval == KERN_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::Semaphore::Semaphore()
|
Threading::Semaphore::Semaphore()
|
||||||
{
|
{
|
||||||
// other platforms explicitly make a thread-private (unshared) semaphore
|
// other platforms explicitly make a thread-private (unshared) semaphore
|
||||||
// here. But it seems Mach doesn't support that.
|
// here. But it seems Mach doesn't support that.
|
||||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0));
|
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::Semaphore::~Semaphore()
|
Threading::Semaphore::~Semaphore()
|
||||||
{
|
{
|
||||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Reset()
|
void Threading::Semaphore::Reset()
|
||||||
{
|
{
|
||||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0));
|
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Post()
|
void Threading::Semaphore::Post()
|
||||||
{
|
{
|
||||||
MACH_CHECK(semaphore_signal(m_sema));
|
MACH_CHECK(semaphore_signal(m_sema));
|
||||||
__atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
__atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Post(int multiple)
|
void Threading::Semaphore::Post(int multiple)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < multiple; ++i) {
|
for (int i = 0; i < multiple; ++i)
|
||||||
MACH_CHECK(semaphore_signal(m_sema));
|
{
|
||||||
}
|
MACH_CHECK(semaphore_signal(m_sema));
|
||||||
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
}
|
||||||
|
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::WaitWithoutYield()
|
void Threading::Semaphore::WaitWithoutYield()
|
||||||
{
|
{
|
||||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||||
MACH_CHECK(semaphore_wait(m_sema));
|
MACH_CHECK(semaphore_wait(m_sema));
|
||||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
// This method is the reason why there has to be a special Darwin
|
// This method is the reason why there has to be a special Darwin
|
||||||
// implementation of Semaphore. Note that semaphore_timedwait() is prone
|
// implementation of Semaphore. Note that semaphore_timedwait() is prone
|
||||||
// to returning with KERN_ABORTED, which basically signifies that some
|
// to returning with KERN_ABORTED, which basically signifies that some
|
||||||
// signal has worken it up. The best official "documentation" for
|
// signal has worken it up. The best official "documentation" for
|
||||||
// semaphore_timedwait() is the way it's used in Grand Central Dispatch,
|
// semaphore_timedwait() is the way it's used in Grand Central Dispatch,
|
||||||
// which is open-source.
|
// which is open-source.
|
||||||
|
|
||||||
// on x86 platforms, mach_absolute_time() returns nanoseconds
|
// on x86 platforms, mach_absolute_time() returns nanoseconds
|
||||||
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
|
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
|
||||||
u64 const kOneThousand = 1000;
|
u64 const kOneThousand = 1000;
|
||||||
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
|
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
|
||||||
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
|
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
|
||||||
mach_timespec_t ts;
|
mach_timespec_t ts;
|
||||||
kern_return_t kr = KERN_ABORTED;
|
kern_return_t kr = KERN_ABORTED;
|
||||||
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
||||||
kr == KERN_ABORTED; now = mach_absolute_time()) {
|
kr == KERN_ABORTED; now = mach_absolute_time())
|
||||||
if (now > deadline) {
|
{
|
||||||
// timed out by definition
|
if (now > deadline)
|
||||||
return false;
|
{
|
||||||
}
|
// timed out by definition
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u64 timeleft = deadline - now;
|
u64 timeleft = deadline - now;
|
||||||
ts.tv_sec = timeleft / kOneBillion;
|
ts.tv_sec = timeleft / kOneBillion;
|
||||||
ts.tv_nsec = timeleft % kOneBillion;
|
ts.tv_nsec = timeleft % kOneBillion;
|
||||||
|
|
||||||
// possible return values of semaphore_timedwait() (from XNU sources):
|
// possible return values of semaphore_timedwait() (from XNU sources):
|
||||||
// internal kernel val -> return value
|
// internal kernel val -> return value
|
||||||
// THREAD_INTERRUPTED -> KERN_ABORTED
|
// THREAD_INTERRUPTED -> KERN_ABORTED
|
||||||
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
|
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
|
||||||
// THREAD_AWAKENED -> KERN_SUCCESS
|
// THREAD_AWAKENED -> KERN_SUCCESS
|
||||||
// THREAD_RESTART -> KERN_TERMINATED
|
// THREAD_RESTART -> KERN_TERMINATED
|
||||||
// default -> KERN_FAILURE
|
// default -> KERN_FAILURE
|
||||||
kr = semaphore_timedwait(m_sema, ts);
|
kr = semaphore_timedwait(m_sema, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kr == KERN_OPERATION_TIMED_OUT) {
|
if (kr == KERN_OPERATION_TIMED_OUT)
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// while it's entirely possible to have KERN_FAILURE here, we should
|
// while it's entirely possible to have KERN_FAILURE here, we should
|
||||||
// probably assert so we can study and correct the actual error here
|
// probably assert so we can study and correct the actual error here
|
||||||
// (the thread dying while someone is wainting for it).
|
// (the thread dying while someone is wainting for it).
|
||||||
MACH_CHECK(kr);
|
MACH_CHECK(kr);
|
||||||
|
|
||||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
|
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
|
||||||
|
@ -155,18 +161,24 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
void Threading::Semaphore::Wait()
|
void Threading::Semaphore::Wait()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
WaitWithoutYield();
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
WaitWithoutYield();
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
WaitWithoutYield();
|
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||||
} else {
|
{
|
||||||
while (!WaitWithoutYield(def_yieldgui_interval)) {
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
YieldToMain();
|
WaitWithoutYield();
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||||
|
{
|
||||||
|
YieldToMain();
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
WaitWithoutYield();
|
WaitWithoutYield();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,29 +191,35 @@ void Threading::Semaphore::Wait()
|
||||||
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
||||||
// reached prior to timeout.
|
// reached prior to timeout.
|
||||||
//
|
//
|
||||||
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
return WaitWithoutYield(timeout);
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
return WaitWithoutYield(timeout);
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
return WaitWithoutYield(timeout);
|
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||||
} else {
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
wxTimeSpan countdown((timeout));
|
return WaitWithoutYield(timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
if (WaitWithoutYield(def_yieldgui_interval))
|
{
|
||||||
break;
|
if (WaitWithoutYield(def_yieldgui_interval))
|
||||||
YieldToMain();
|
break;
|
||||||
countdown -= def_yieldgui_interval;
|
YieldToMain();
|
||||||
} while (countdown.GetMilliseconds() > 0);
|
countdown -= def_yieldgui_interval;
|
||||||
|
} while (countdown.GetMilliseconds() > 0);
|
||||||
|
|
||||||
return countdown.GetMilliseconds() > 0;
|
return countdown.GetMilliseconds() > 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,22 +238,22 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
||||||
// POSIX threads), this should work. -- aktau
|
// POSIX threads), this should work. -- aktau
|
||||||
void Threading::Semaphore::WaitNoCancel()
|
void Threading::Semaphore::WaitNoCancel()
|
||||||
{
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||||
Wait();
|
Wait();
|
||||||
pthread_setcancelstate(oldstate, NULL);
|
pthread_setcancelstate(oldstate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout)
|
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||||
Wait(timeout);
|
Wait(timeout);
|
||||||
pthread_setcancelstate(oldstate, NULL);
|
pthread_setcancelstate(oldstate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Threading::Semaphore::Count()
|
int Threading::Semaphore::Count()
|
||||||
{
|
{
|
||||||
return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST);
|
return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,27 +29,27 @@
|
||||||
|
|
||||||
__forceinline void Threading::Sleep(int ms)
|
__forceinline void Threading::Sleep(int ms)
|
||||||
{
|
{
|
||||||
usleep(1000 * ms);
|
usleep(1000 * ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
|
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
|
||||||
// improve performance and reduce cpu power consumption.
|
// improve performance and reduce cpu power consumption.
|
||||||
__forceinline void Threading::SpinWait()
|
__forceinline void Threading::SpinWait()
|
||||||
{
|
{
|
||||||
// If this doesn't compile you can just comment it out (it only serves as a
|
// If this doesn't compile you can just comment it out (it only serves as a
|
||||||
// performance hint and isn't required).
|
// performance hint and isn't required).
|
||||||
__asm__("pause");
|
__asm__("pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void Threading::EnableHiresScheduler()
|
__forceinline void Threading::EnableHiresScheduler()
|
||||||
{
|
{
|
||||||
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
|
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
|
||||||
// implemented yet though (and not sure if useful for pcsx2).
|
// implemented yet though (and not sure if useful for pcsx2).
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void Threading::DisableHiresScheduler()
|
__forceinline void Threading::DisableHiresScheduler()
|
||||||
{
|
{
|
||||||
// see EnableHiresScheduler()
|
// see EnableHiresScheduler()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just like on Windows, this is not really the number of ticks per second,
|
// Just like on Windows, this is not really the number of ticks per second,
|
||||||
|
@ -58,27 +58,28 @@ __forceinline void Threading::DisableHiresScheduler()
|
||||||
// doing this will of course yield precision loss.
|
// doing this will of course yield precision loss.
|
||||||
u64 Threading::GetThreadTicksPerSecond()
|
u64 Threading::GetThreadTicksPerSecond()
|
||||||
{
|
{
|
||||||
return 1000000; // the *CpuTime() functions return values in microseconds
|
return 1000000; // the *CpuTime() functions return values in microseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the CPU time used by the current thread (both system and user), in
|
// gets the CPU time used by the current thread (both system and user), in
|
||||||
// microseconds, returns 0 on failure
|
// microseconds, returns 0 on failure
|
||||||
static u64 getthreadtime(thread_port_t thread)
|
static u64 getthreadtime(thread_port_t thread)
|
||||||
{
|
{
|
||||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||||
thread_basic_info_data_t info;
|
thread_basic_info_data_t info;
|
||||||
|
|
||||||
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
||||||
(thread_info_t)&info, &count);
|
(thread_info_t)&info, &count);
|
||||||
if (kr != KERN_SUCCESS) {
|
if (kr != KERN_SUCCESS)
|
||||||
return 0;
|
{
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// add system and user time
|
// add system and user time
|
||||||
return (u64)info.user_time.seconds * (u64)1e6 +
|
return (u64)info.user_time.seconds * (u64)1e6 +
|
||||||
(u64)info.user_time.microseconds +
|
(u64)info.user_time.microseconds +
|
||||||
(u64)info.system_time.seconds * (u64)1e6 +
|
(u64)info.system_time.seconds * (u64)1e6 +
|
||||||
(u64)info.system_time.microseconds;
|
(u64)info.system_time.microseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current timestamp (not relative to a real world clock) in
|
// Returns the current timestamp (not relative to a real world clock) in
|
||||||
|
@ -88,44 +89,45 @@ static u64 getthreadtime(thread_port_t thread)
|
||||||
// not very good.
|
// not very good.
|
||||||
u64 Threading::GetThreadCpuTime()
|
u64 Threading::GetThreadCpuTime()
|
||||||
{
|
{
|
||||||
// we could also use mach_thread_self() and mach_port_deallocate(), but
|
// we could also use mach_thread_self() and mach_port_deallocate(), but
|
||||||
// that calls upon mach traps (kinda like system calls). Unless I missed
|
// that calls upon mach traps (kinda like system calls). Unless I missed
|
||||||
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
|
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
|
||||||
// to be user-space instead. In contract,
|
// to be user-space instead. In contract,
|
||||||
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
|
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
|
||||||
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
|
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
|
||||||
return us * 10ULL;
|
return us * 10ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Threading::pxThread::GetCpuTime() const
|
u64 Threading::pxThread::GetCpuTime() const
|
||||||
{
|
{
|
||||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||||
// which typically would be an OS-provided scalar or some sort).
|
// which typically would be an OS-provided scalar or some sort).
|
||||||
if (!m_native_id) {
|
if (!m_native_id)
|
||||||
return 0;
|
{
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return getthreadtime((thread_port_t)m_native_id) * 10ULL;
|
return getthreadtime((thread_port_t)m_native_id) * 10ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||||
{
|
{
|
||||||
m_native_id = (uptr)mach_thread_self();
|
m_native_id = (uptr)mach_thread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||||
{
|
{
|
||||||
// cleanup of handles that were upened in
|
// cleanup of handles that were upened in
|
||||||
// _platform_specific_OnStartInThread
|
// _platform_specific_OnStartInThread
|
||||||
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
|
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// name can be up to 16 bytes
|
// name can be up to 16 bytes
|
||||||
void Threading::SetNameOfCurrentThread(const char *name)
|
void Threading::SetNameOfCurrentThread(const char* name)
|
||||||
{
|
{
|
||||||
pthread_setname_np(name);
|
pthread_setname_np(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -61,44 +61,48 @@
|
||||||
// method is not implemented! You must implement it yourself if you want to use it:
|
// method is not implemented! You must implement it yourself if you want to use it:
|
||||||
// EnumToString(value);
|
// EnumToString(value);
|
||||||
//
|
//
|
||||||
#define ImplementEnumOperators(enumName) \
|
#define ImplementEnumOperators(enumName) \
|
||||||
static __fi enumName &operator++(enumName &src) \
|
static __fi enumName& operator++(enumName& src) \
|
||||||
{ \
|
{ \
|
||||||
src = (enumName)((int)src + 1); \
|
src = (enumName)((int)src + 1); \
|
||||||
return src; \
|
return src; \
|
||||||
} \
|
} \
|
||||||
static __fi enumName &operator--(enumName &src) \
|
\
|
||||||
{ \
|
static __fi enumName& operator--(enumName& src) \
|
||||||
src = (enumName)((int)src - 1); \
|
{ \
|
||||||
return src; \
|
src = (enumName)((int)src - 1); \
|
||||||
} \
|
return src; \
|
||||||
static __fi enumName operator++(enumName &src, int) \
|
} \
|
||||||
{ \
|
\
|
||||||
enumName orig = src; \
|
static __fi enumName operator++(enumName& src, int) \
|
||||||
src = (enumName)((int)src + 1); \
|
{ \
|
||||||
return orig; \
|
enumName orig = src; \
|
||||||
} \
|
src = (enumName)((int)src + 1); \
|
||||||
static __fi enumName operator--(enumName &src, int) \
|
return orig; \
|
||||||
{ \
|
} \
|
||||||
enumName orig = src; \
|
\
|
||||||
src = (enumName)((int)src - 1); \
|
static __fi enumName operator--(enumName& src, int) \
|
||||||
return orig; \
|
{ \
|
||||||
} \
|
enumName orig = src; \
|
||||||
\
|
src = (enumName)((int)src - 1); \
|
||||||
static __fi bool operator<(const enumName &left, const pxEnumEnd_t &) { return (int)left < enumName##_COUNT; } \
|
return orig; \
|
||||||
static __fi bool operator!=(const enumName &left, const pxEnumEnd_t &) { return (int)left != enumName##_COUNT; } \
|
} \
|
||||||
static __fi bool operator==(const enumName &left, const pxEnumEnd_t &) { return (int)left == enumName##_COUNT; } \
|
\
|
||||||
\
|
static __fi bool operator<(const enumName& left, const pxEnumEnd_t&) { return (int)left < enumName##_COUNT; } \
|
||||||
static __fi bool EnumIsValid(enumName id) \
|
static __fi bool operator!=(const enumName& left, const pxEnumEnd_t&) { return (int)left != enumName##_COUNT; } \
|
||||||
{ \
|
static __fi bool operator==(const enumName& left, const pxEnumEnd_t&) { return (int)left == enumName##_COUNT; } \
|
||||||
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
\
|
||||||
} \
|
static __fi bool EnumIsValid(enumName id) \
|
||||||
static __fi void EnumAssert(enumName id) \
|
{ \
|
||||||
{ \
|
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
||||||
pxAssert(EnumIsValid(id)); \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
static __fi void EnumAssert(enumName id) \
|
||||||
extern const wxChar *EnumToString(enumName id)
|
{ \
|
||||||
|
pxAssert(EnumIsValid(id)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
extern const wxChar* EnumToString(enumName id)
|
||||||
|
|
||||||
class pxEnumEnd_t
|
class pxEnumEnd_t
|
||||||
{
|
{
|
||||||
|
@ -130,9 +134,9 @@ static const pxEnumEnd_t pxEnumEnd = {};
|
||||||
//
|
//
|
||||||
#ifndef DeclareNoncopyableObject
|
#ifndef DeclareNoncopyableObject
|
||||||
#define DeclareNoncopyableObject(classname) \
|
#define DeclareNoncopyableObject(classname) \
|
||||||
private: \
|
private: \
|
||||||
explicit classname(const classname &); \
|
explicit classname(const classname&); \
|
||||||
classname &operator=(const classname &)
|
classname& operator=(const classname&)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,19 +148,19 @@ private: \
|
||||||
class ScopedBool
|
class ScopedBool
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool *m_boolme;
|
bool* m_boolme;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedBool(bool &boolme)
|
ScopedBool(bool& boolme)
|
||||||
{
|
{
|
||||||
boolme = true;
|
boolme = true;
|
||||||
m_boolme = &boolme;
|
m_boolme = &boolme;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScopedBool()
|
~ScopedBool()
|
||||||
{
|
{
|
||||||
*m_boolme = false;
|
*m_boolme = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -218,7 +222,7 @@ public:
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstring> // string.h under c++
|
#include <cstring> // string.h under c++
|
||||||
#include <cstdio> // stdio.h under c++
|
#include <cstdio> // stdio.h under c++
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -262,12 +266,12 @@ static const s64 _4gb = _1gb * 4;
|
||||||
#define pxE_dev(english) pxExpandMsg((english))
|
#define pxE_dev(english) pxExpandMsg((english))
|
||||||
|
|
||||||
|
|
||||||
extern const wxChar *__fastcall pxExpandMsg(const wxChar *message);
|
extern const wxChar* __fastcall pxExpandMsg(const wxChar* message);
|
||||||
extern const wxChar *__fastcall pxGetTranslation(const wxChar *message);
|
extern const wxChar* __fastcall pxGetTranslation(const wxChar* message);
|
||||||
extern bool pxIsEnglish(int id);
|
extern bool pxIsEnglish(int id);
|
||||||
|
|
||||||
extern wxString fromUTF8(const char *src);
|
extern wxString fromUTF8(const char* src);
|
||||||
extern wxString fromAscii(const char *src);
|
extern wxString fromAscii(const char* src);
|
||||||
|
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
class IEmbeddedImage
|
class IEmbeddedImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual const wxImage &Get() = 0;
|
virtual const wxImage& Get() = 0;
|
||||||
virtual wxImage Scale(int width, int height) = 0;
|
virtual wxImage Scale(int width, int height) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -42,79 +42,80 @@ template <typename ImageType>
|
||||||
class EmbeddedImage : public IEmbeddedImage
|
class EmbeddedImage : public IEmbeddedImage
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxImage m_Image;
|
wxImage m_Image;
|
||||||
const wxSize m_ResampleTo;
|
const wxSize m_ResampleTo;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Internal function used to ensure the image is loaded before returning the image
|
// Internal function used to ensure the image is loaded before returning the image
|
||||||
// handle (called from all methods that return an image handle).
|
// handle (called from all methods that return an image handle).
|
||||||
//
|
//
|
||||||
void _loadImage()
|
void _loadImage()
|
||||||
{
|
{
|
||||||
if (!m_Image.Ok()) {
|
if (!m_Image.Ok())
|
||||||
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
{
|
||||||
m_Image.LoadFile(joe, ImageType::GetFormat());
|
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
||||||
|
m_Image.LoadFile(joe, ImageType::GetFormat());
|
||||||
|
|
||||||
if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight()))
|
if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight()))
|
||||||
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
|
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmbeddedImage()
|
EmbeddedImage()
|
||||||
: m_Image()
|
: m_Image()
|
||||||
, m_ResampleTo(wxDefaultSize)
|
, m_ResampleTo(wxDefaultSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Constructor for creating an embedded image that gets resampled to the specified size when
|
// Constructor for creating an embedded image that gets resampled to the specified size when
|
||||||
// loaded.
|
// loaded.
|
||||||
//
|
//
|
||||||
// Implementation Note: This function uses wxWidgets ResamplBox method to resize the image.
|
// Implementation Note: This function uses wxWidgets ResamplBox method to resize the image.
|
||||||
// wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down-
|
// wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down-
|
||||||
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
|
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
|
||||||
// results.
|
// results.
|
||||||
//
|
//
|
||||||
EmbeddedImage(int newWidth, int newHeight)
|
EmbeddedImage(int newWidth, int newHeight)
|
||||||
: m_Image()
|
: m_Image()
|
||||||
, m_ResampleTo(newWidth, newHeight)
|
, m_ResampleTo(newWidth, newHeight)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Loads and retrieves the embedded image. The embedded image is only loaded from its em-
|
// Loads and retrieves the embedded image. The embedded image is only loaded from its em-
|
||||||
// bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use
|
// bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use
|
||||||
// the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once,
|
// the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once,
|
||||||
// and only happens when the image is actually fetched. Simply creating an instance
|
// and only happens when the image is actually fetched. Simply creating an instance
|
||||||
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
|
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
|
||||||
//
|
//
|
||||||
const wxImage &Get()
|
const wxImage& Get()
|
||||||
{
|
{
|
||||||
_loadImage();
|
_loadImage();
|
||||||
return m_Image;
|
return m_Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxIcon GetIcon()
|
wxIcon GetIcon()
|
||||||
{
|
{
|
||||||
wxIcon retval;
|
wxIcon retval;
|
||||||
retval.CopyFromBitmap(Get());
|
retval.CopyFromBitmap(Get());
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
|
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
|
||||||
// is left unmodified).
|
// is left unmodified).
|
||||||
//
|
//
|
||||||
|
|
||||||
wxImage Scale(int width, int height)
|
wxImage Scale(int width, int height)
|
||||||
{
|
{
|
||||||
_loadImage();
|
_loadImage();
|
||||||
// Not strictly necessary - wxWidgets does the dimensions check anyway.
|
// Not strictly necessary - wxWidgets does the dimensions check anyway.
|
||||||
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
|
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
|
||||||
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
|
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
|
||||||
else
|
else
|
||||||
return m_Image;
|
return m_Image;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,54 +26,54 @@ template <typename ListenerType>
|
||||||
class EventSource
|
class EventSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename ListenerType::EvtParams EvtParams;
|
typedef typename ListenerType::EvtParams EvtParams;
|
||||||
typedef typename std::list<ListenerType *> ListenerList;
|
typedef typename std::list<ListenerType*> ListenerList;
|
||||||
typedef typename ListenerList::iterator ListenerIterator;
|
typedef typename ListenerList::iterator ListenerIterator;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef typename ListenerList::const_iterator ConstIterator;
|
typedef typename ListenerList::const_iterator ConstIterator;
|
||||||
|
|
||||||
ListenerList m_listeners;
|
ListenerList m_listeners;
|
||||||
|
|
||||||
// This is a cached copy of the listener list used to handle standard dispatching, which
|
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||||
// allows for self-modification of the EventSource's listener list by the listeners.
|
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||||
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||||
ListenerList m_cache_copy;
|
ListenerList m_cache_copy;
|
||||||
bool m_cache_valid;
|
bool m_cache_valid;
|
||||||
|
|
||||||
Threading::Mutex m_listeners_lock;
|
Threading::Mutex m_listeners_lock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EventSource()
|
EventSource()
|
||||||
{
|
{
|
||||||
m_cache_valid = false;
|
m_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~EventSource() = default;
|
virtual ~EventSource() = default;
|
||||||
|
|
||||||
virtual ListenerIterator Add(ListenerType &listener);
|
virtual ListenerIterator Add(ListenerType& listener);
|
||||||
virtual void Remove(ListenerType &listener);
|
virtual void Remove(ListenerType& listener);
|
||||||
virtual void Remove(const ListenerIterator &listenerHandle);
|
virtual void Remove(const ListenerIterator& listenerHandle);
|
||||||
|
|
||||||
void Add(ListenerType *listener)
|
void Add(ListenerType* listener)
|
||||||
{
|
{
|
||||||
if (listener == NULL)
|
if (listener == NULL)
|
||||||
return;
|
return;
|
||||||
Add(*listener);
|
Add(*listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Remove(ListenerType *listener)
|
void Remove(ListenerType* listener)
|
||||||
{
|
{
|
||||||
if (listener == NULL)
|
if (listener == NULL)
|
||||||
return;
|
return;
|
||||||
Remove(*listener);
|
Remove(*listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispatch(const EvtParams ¶ms);
|
void Dispatch(const EvtParams& params);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ListenerIterator _AddFast_without_lock(ListenerType &listener);
|
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
|
||||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams ¶ms);
|
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -86,9 +86,9 @@ template <typename EvtParams>
|
||||||
class IEventDispatcher
|
class IEventDispatcher
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
IEventDispatcher() {}
|
IEventDispatcher() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~IEventDispatcher() = default;
|
virtual ~IEventDispatcher() = default;
|
||||||
virtual void DispatchEvent(const EvtParams ¶ms) = 0;
|
virtual void DispatchEvent(const EvtParams& params) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,79 +20,92 @@
|
||||||
using Threading::ScopedLock;
|
using Threading::ScopedLock;
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType &listener)
|
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
|
||||||
{
|
{
|
||||||
ScopedLock locker(m_listeners_lock);
|
ScopedLock locker(m_listeners_lock);
|
||||||
|
|
||||||
// Check for duplicates before adding the event.
|
// Check for duplicates before adding the event.
|
||||||
if (IsDebugBuild) {
|
if (IsDebugBuild)
|
||||||
ListenerIterator iter = m_listeners.begin();
|
{
|
||||||
while (iter != m_listeners.end()) {
|
ListenerIterator iter = m_listeners.begin();
|
||||||
if ((*iter) == &listener)
|
while (iter != m_listeners.end())
|
||||||
return iter;
|
{
|
||||||
++iter;
|
if ((*iter) == &listener)
|
||||||
}
|
return iter;
|
||||||
}
|
++iter;
|
||||||
return _AddFast_without_lock(listener);
|
}
|
||||||
|
}
|
||||||
|
return _AddFast_without_lock(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
void EventSource<ListenerType>::Remove(ListenerType &listener)
|
void EventSource<ListenerType>::Remove(ListenerType& listener)
|
||||||
{
|
{
|
||||||
ScopedLock locker(m_listeners_lock);
|
ScopedLock locker(m_listeners_lock);
|
||||||
m_cache_valid = false;
|
m_cache_valid = false;
|
||||||
m_listeners.remove(&listener);
|
m_listeners.remove(&listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
void EventSource<ListenerType>::Remove(const ListenerIterator &listenerHandle)
|
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
|
||||||
{
|
{
|
||||||
ScopedLock locker(m_listeners_lock);
|
ScopedLock locker(m_listeners_lock);
|
||||||
m_cache_valid = false;
|
m_cache_valid = false;
|
||||||
m_listeners.erase(listenerHandle);
|
m_listeners.erase(listenerHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType &listener)
|
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
|
||||||
{
|
{
|
||||||
m_cache_valid = false;
|
m_cache_valid = false;
|
||||||
m_listeners.push_front(&listener);
|
m_listeners.push_front(&listener);
|
||||||
return m_listeners.begin();
|
return m_listeners.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams &evtparams)
|
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
||||||
{
|
{
|
||||||
while (iter != iend) {
|
while (iter != iend)
|
||||||
try {
|
{
|
||||||
(*iter)->DispatchEvent(evtparams);
|
try
|
||||||
} catch (Exception::RuntimeError &ex) {
|
{
|
||||||
if (IsDevBuild) {
|
(*iter)->DispatchEvent(evtparams);
|
||||||
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
}
|
||||||
} else {
|
catch (Exception::RuntimeError& ex)
|
||||||
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
{
|
||||||
}
|
if (IsDevBuild)
|
||||||
} catch (BaseException &ex) {
|
{
|
||||||
if (IsDevBuild) {
|
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
||||||
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
}
|
||||||
throw;
|
else
|
||||||
}
|
{
|
||||||
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage());
|
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||||
}
|
}
|
||||||
++iter;
|
}
|
||||||
}
|
catch (BaseException& ex)
|
||||||
|
{
|
||||||
|
if (IsDevBuild)
|
||||||
|
{
|
||||||
|
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
void EventSource<ListenerType>::Dispatch(const EvtParams &evtparams)
|
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
||||||
{
|
{
|
||||||
if (!m_cache_valid) {
|
if (!m_cache_valid)
|
||||||
m_cache_copy = m_listeners;
|
{
|
||||||
m_cache_valid = true;
|
m_cache_copy = m_listeners;
|
||||||
}
|
m_cache_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_cache_copy.empty())
|
if (m_cache_copy.empty())
|
||||||
return;
|
return;
|
||||||
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,28 +42,28 @@ Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
|
||||||
// That's ok. What we don't want is the *same* thread recurse-asserting.
|
// That's ok. What we don't want is the *same* thread recurse-asserting.
|
||||||
static DeclareTls(int) s_assert_guard(0);
|
static DeclareTls(int) s_assert_guard(0);
|
||||||
|
|
||||||
pxDoAssertFnType *pxDoAssert = pxAssertImpl_LogIt;
|
pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
|
||||||
|
|
||||||
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
||||||
// response times from the Output window...
|
// response times from the Output window...
|
||||||
wxString DiagnosticOrigin::ToString(const wxChar *msg) const
|
wxString DiagnosticOrigin::ToString(const wxChar* msg) const
|
||||||
{
|
{
|
||||||
FastFormatUnicode message;
|
FastFormatUnicode message;
|
||||||
|
|
||||||
message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line);
|
message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line);
|
||||||
|
|
||||||
if (function != NULL)
|
if (function != NULL)
|
||||||
message.Write(" Function: %s\n", function);
|
message.Write(" Function: %s\n", function);
|
||||||
|
|
||||||
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
|
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
|
||||||
|
|
||||||
if (condition != NULL)
|
if (condition != NULL)
|
||||||
message.Write(L" Condition: %ls\n", condition);
|
message.Write(L" Condition: %ls\n", condition);
|
||||||
|
|
||||||
if (msg != NULL)
|
if (msg != NULL)
|
||||||
message.Write(L" Message: %ls\n", msg);
|
message.Write(L" Message: %ls\n", msg);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,191 +71,196 @@ wxString DiagnosticOrigin::ToString(const wxChar *msg) const
|
||||||
void pxTrap()
|
void pxTrap()
|
||||||
{
|
{
|
||||||
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
#elif defined(__WXMAC__) && !defined(__DARWIN__)
|
#elif defined(__WXMAC__) && !defined(__DARWIN__)
|
||||||
#if __powerc
|
#if __powerc
|
||||||
Debugger();
|
Debugger();
|
||||||
#else
|
#else
|
||||||
SysBreak();
|
SysBreak();
|
||||||
#endif
|
#endif
|
||||||
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
|
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
|
||||||
Debugger();
|
Debugger();
|
||||||
#elif defined(__UNIX__)
|
#elif defined(__UNIX__)
|
||||||
raise(SIGTRAP);
|
raise(SIGTRAP);
|
||||||
#else
|
#else
|
||||||
// TODO
|
// TODO
|
||||||
#endif // Win/Unix
|
#endif // Win/Unix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool pxAssertImpl_LogIt(const DiagnosticOrigin &origin, const wxChar *msg)
|
bool pxAssertImpl_LogIt(const DiagnosticOrigin& origin, const wxChar* msg)
|
||||||
{
|
{
|
||||||
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
||||||
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
|
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
|
||||||
pxTrap();
|
pxTrap();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg)
|
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg)
|
||||||
{
|
{
|
||||||
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
|
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
|
||||||
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
||||||
|
|
||||||
RecursionGuard guard(s_assert_guard);
|
RecursionGuard guard(s_assert_guard);
|
||||||
if (guard.Counter > 2) {
|
if (guard.Counter > 2)
|
||||||
return pxTrap();
|
{
|
||||||
}
|
return pxTrap();
|
||||||
|
}
|
||||||
|
|
||||||
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
|
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
|
||||||
// it difficult to use the debug build (compilation failures). To handle these I've had to
|
// it difficult to use the debug build (compilation failures). To handle these I've had to
|
||||||
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
|
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
|
||||||
// PCSX2 itself is compiled in debug mode (assertions enabled).
|
// PCSX2 itself is compiled in debug mode (assertions enabled).
|
||||||
|
|
||||||
bool trapit;
|
bool trapit;
|
||||||
|
|
||||||
if (pxDoAssert == NULL) {
|
if (pxDoAssert == NULL)
|
||||||
// Note: Format uses MSVC's syntax for output window hotlinking.
|
{
|
||||||
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
// Note: Format uses MSVC's syntax for output window hotlinking.
|
||||||
} else {
|
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
||||||
trapit = pxDoAssert(origin, msg.wc_str());
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
trapit = pxDoAssert(origin, msg.wc_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (trapit) {
|
if (trapit)
|
||||||
pxTrap();
|
{
|
||||||
}
|
pxTrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BaseException (implementations)
|
// BaseException (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
BaseException &BaseException::SetBothMsgs(const wxChar *msg_diag)
|
BaseException& BaseException::SetBothMsgs(const wxChar* msg_diag)
|
||||||
{
|
{
|
||||||
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
|
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
|
||||||
return SetDiagMsg(msg_diag);
|
return SetDiagMsg(msg_diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseException &BaseException::SetDiagMsg(const wxString &msg_diag)
|
BaseException& BaseException::SetDiagMsg(const wxString& msg_diag)
|
||||||
{
|
{
|
||||||
m_message_diag = msg_diag;
|
m_message_diag = msg_diag;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseException &BaseException::SetUserMsg(const wxString &msg_user)
|
BaseException& BaseException::SetUserMsg(const wxString& msg_user)
|
||||||
{
|
{
|
||||||
m_message_user = msg_user;
|
m_message_user = msg_user;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString BaseException::FormatDiagnosticMessage() const
|
wxString BaseException::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
return m_message_diag;
|
return m_message_diag;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString BaseException::FormatDisplayMessage() const
|
wxString BaseException::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
|
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Exception::RuntimeError (implementations)
|
// Exception::RuntimeError (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Exception::RuntimeError::RuntimeError(const std::runtime_error &ex, const wxString &prefix)
|
Exception::RuntimeError::RuntimeError(const std::runtime_error& ex, const wxString& prefix)
|
||||||
{
|
{
|
||||||
IsSilent = false;
|
IsSilent = false;
|
||||||
|
|
||||||
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
|
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
|
||||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||||
WX_STR(fromUTF8(ex.what()))));
|
WX_STR(fromUTF8(ex.what()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception::RuntimeError::RuntimeError(const std::exception &ex, const wxString &prefix)
|
Exception::RuntimeError::RuntimeError(const std::exception& ex, const wxString& prefix)
|
||||||
{
|
{
|
||||||
IsSilent = false;
|
IsSilent = false;
|
||||||
|
|
||||||
SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
|
SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
|
||||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||||
WX_STR(fromUTF8(ex.what()))));
|
WX_STR(fromUTF8(ex.what()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Exception::OutOfMemory (implementations)
|
// Exception::OutOfMemory (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Exception::OutOfMemory::OutOfMemory(const wxString &allocdesc)
|
Exception::OutOfMemory::OutOfMemory(const wxString& allocdesc)
|
||||||
{
|
{
|
||||||
AllocDescription = allocdesc;
|
AllocDescription = allocdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
|
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retmsg;
|
FastFormatUnicode retmsg;
|
||||||
retmsg.Write(L"Out of memory");
|
retmsg.Write(L"Out of memory");
|
||||||
if (!AllocDescription.IsEmpty())
|
if (!AllocDescription.IsEmpty())
|
||||||
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
|
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
|
||||||
|
|
||||||
if (!m_message_diag.IsEmpty())
|
if (!m_message_diag.IsEmpty())
|
||||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||||
|
|
||||||
return retmsg;
|
return retmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::OutOfMemory::FormatDisplayMessage() const
|
wxString Exception::OutOfMemory::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retmsg;
|
FastFormatUnicode retmsg;
|
||||||
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
|
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
|
||||||
|
|
||||||
if (!m_message_user.IsEmpty())
|
if (!m_message_user.IsEmpty())
|
||||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
|
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
|
||||||
|
|
||||||
return retmsg;
|
return retmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Exception::VirtualMemoryMapConflict (implementations)
|
// Exception::VirtualMemoryMapConflict (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString &allocdesc)
|
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString& allocdesc)
|
||||||
{
|
{
|
||||||
AllocDescription = allocdesc;
|
AllocDescription = allocdesc;
|
||||||
m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.");
|
m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.");
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
|
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retmsg;
|
FastFormatUnicode retmsg;
|
||||||
retmsg.Write(L"Virtual memory map failed");
|
retmsg.Write(L"Virtual memory map failed");
|
||||||
if (!AllocDescription.IsEmpty())
|
if (!AllocDescription.IsEmpty())
|
||||||
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
|
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
|
||||||
|
|
||||||
if (!m_message_diag.IsEmpty())
|
if (!m_message_diag.IsEmpty())
|
||||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||||
|
|
||||||
return retmsg;
|
return retmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
|
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retmsg;
|
FastFormatUnicode retmsg;
|
||||||
retmsg.Write(L"%s",
|
retmsg.Write(L"%s",
|
||||||
pxE(L"There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs."));
|
pxE(L"There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs."));
|
||||||
|
|
||||||
if (!m_message_diag.IsEmpty())
|
if (!m_message_diag.IsEmpty())
|
||||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
|
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
|
||||||
|
|
||||||
return retmsg;
|
return retmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
|
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
return L"Action canceled: " + m_message_diag;
|
return L"Action canceled: " + m_message_diag;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::CancelEvent::FormatDisplayMessage() const
|
wxString Exception::CancelEvent::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
return L"Action canceled: " + m_message_diag;
|
return L"Action canceled: " + m_message_diag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -263,40 +268,40 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString Exception::BadStream::FormatDiagnosticMessage() const
|
wxString Exception::BadStream::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
_formatDiagMsg(retval);
|
_formatDiagMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::BadStream::FormatDisplayMessage() const
|
wxString Exception::BadStream::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
_formatUserMsg(retval);
|
_formatUserMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode &dest) const
|
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode& dest) const
|
||||||
{
|
{
|
||||||
dest.Write(L"Path: ");
|
dest.Write(L"Path: ");
|
||||||
if (!StreamName.IsEmpty())
|
if (!StreamName.IsEmpty())
|
||||||
dest.Write(L"%s", WX_STR(StreamName));
|
dest.Write(L"%s", WX_STR(StreamName));
|
||||||
else
|
else
|
||||||
dest.Write(L"[Unnamed or unknown]");
|
dest.Write(L"[Unnamed or unknown]");
|
||||||
|
|
||||||
if (!m_message_diag.IsEmpty())
|
if (!m_message_diag.IsEmpty())
|
||||||
dest.Write(L"\n%s", WX_STR(m_message_diag));
|
dest.Write(L"\n%s", WX_STR(m_message_diag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const
|
void Exception::BadStream::_formatUserMsg(FastFormatUnicode& dest) const
|
||||||
{
|
{
|
||||||
dest.Write(_("Path: "));
|
dest.Write(_("Path: "));
|
||||||
if (!StreamName.IsEmpty())
|
if (!StreamName.IsEmpty())
|
||||||
dest.Write(L"%s", WX_STR(StreamName));
|
dest.Write(L"%s", WX_STR(StreamName));
|
||||||
else
|
else
|
||||||
dest.Write(_("[Unnamed or unknown]"));
|
dest.Write(_("[Unnamed or unknown]"));
|
||||||
|
|
||||||
if (!m_message_user.IsEmpty())
|
if (!m_message_user.IsEmpty())
|
||||||
dest.Write(L"\n%s", WX_STR(m_message_user));
|
dest.Write(L"\n%s", WX_STR(m_message_user));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -304,19 +309,19 @@ void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
|
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write("File could not be created.");
|
retval.Write("File could not be created.");
|
||||||
_formatDiagMsg(retval);
|
_formatDiagMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write(_("A file could not be created."));
|
retval.Write(_("A file could not be created."));
|
||||||
retval.Write("\n");
|
retval.Write("\n");
|
||||||
_formatUserMsg(retval);
|
_formatUserMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -324,19 +329,19 @@ wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
|
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write("File not found.\n");
|
retval.Write("File not found.\n");
|
||||||
_formatDiagMsg(retval);
|
_formatDiagMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::FileNotFound::FormatDisplayMessage() const
|
wxString Exception::FileNotFound::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write(_("File not found."));
|
retval.Write(_("File not found."));
|
||||||
retval.Write("\n");
|
retval.Write("\n");
|
||||||
_formatUserMsg(retval);
|
_formatUserMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -344,19 +349,19 @@ wxString Exception::FileNotFound::FormatDisplayMessage() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
|
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write("Permission denied to file.\n");
|
retval.Write("Permission denied to file.\n");
|
||||||
_formatDiagMsg(retval);
|
_formatDiagMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::AccessDenied::FormatDisplayMessage() const
|
wxString Exception::AccessDenied::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
|
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
|
||||||
retval.Write("\n");
|
retval.Write("\n");
|
||||||
_formatUserMsg(retval);
|
_formatUserMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -364,19 +369,19 @@ wxString Exception::AccessDenied::FormatDisplayMessage() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
|
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write("Unexpected end of file or stream.\n");
|
retval.Write("Unexpected end of file or stream.\n");
|
||||||
_formatDiagMsg(retval);
|
_formatDiagMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::EndOfStream::FormatDisplayMessage() const
|
wxString Exception::EndOfStream::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode retval;
|
FastFormatUnicode retval;
|
||||||
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
|
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
|
||||||
retval.Write("\n");
|
retval.Write("\n");
|
||||||
_formatUserMsg(retval);
|
_formatUserMsg(retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -385,34 +390,35 @@ wxString Exception::EndOfStream::FormatDisplayMessage() const
|
||||||
|
|
||||||
// Translates an Errno code into an exception.
|
// Translates an Errno code into an exception.
|
||||||
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
|
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
|
||||||
BaseException *Exception::FromErrno(const wxString &streamname, int errcode)
|
BaseException* Exception::FromErrno(const wxString& streamname, int errcode)
|
||||||
{
|
{
|
||||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||||
|
|
||||||
switch (errcode) {
|
switch (errcode)
|
||||||
case EINVAL:
|
{
|
||||||
pxFailDev(L"Invalid argument");
|
case EINVAL:
|
||||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
pxFailDev(L"Invalid argument");
|
||||||
|
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
||||||
|
|
||||||
case EACCES: // Access denied!
|
case EACCES: // Access denied!
|
||||||
return new Exception::AccessDenied(streamname);
|
return new Exception::AccessDenied(streamname);
|
||||||
|
|
||||||
case EMFILE: // Too many open files!
|
case EMFILE: // Too many open files!
|
||||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
|
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
|
||||||
|
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
|
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
|
||||||
|
|
||||||
case ENOENT: // File not found!
|
case ENOENT: // File not found!
|
||||||
return new Exception::FileNotFound(streamname);
|
return new Exception::FileNotFound(streamname);
|
||||||
|
|
||||||
case EPIPE:
|
case EPIPE:
|
||||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
|
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
|
||||||
|
|
||||||
case EBADF:
|
case EBADF:
|
||||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
|
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
|
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,115 +32,121 @@ void pxTrap();
|
||||||
// friendly error log in their wake.
|
// friendly error log in their wake.
|
||||||
//
|
//
|
||||||
// Note: Console can also fire an Exception::OutOfMemory
|
// Note: Console can also fire an Exception::OutOfMemory
|
||||||
#define __DESTRUCTOR_CATCHALL(funcname) \
|
#define __DESTRUCTOR_CATCHALL(funcname) \
|
||||||
catch (BaseException & ex) \
|
catch (BaseException & ex) \
|
||||||
{ \
|
{ \
|
||||||
try { \
|
try \
|
||||||
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
{ \
|
||||||
Console.Error(ex.FormatDiagnosticMessage()); \
|
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
||||||
} catch (...) { \
|
Console.Error(ex.FormatDiagnosticMessage()); \
|
||||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
} \
|
||||||
} \
|
catch (...) \
|
||||||
} \
|
{ \
|
||||||
catch (std::exception & ex) \
|
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||||
{ \
|
} \
|
||||||
try { \
|
} \
|
||||||
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
catch (std::exception & ex) \
|
||||||
Console.Error(ex.what()); \
|
{ \
|
||||||
} catch (...) { \
|
try \
|
||||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
{ \
|
||||||
} \
|
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
||||||
} \
|
Console.Error(ex.what()); \
|
||||||
catch (...) \
|
} \
|
||||||
{ \
|
catch (...) \
|
||||||
/* Unreachable code */ \
|
{ \
|
||||||
}
|
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
catch (...) \
|
||||||
|
{ \
|
||||||
|
/* Unreachable code */ \
|
||||||
|
}
|
||||||
|
|
||||||
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
|
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
class BaseException;
|
class BaseException;
|
||||||
|
|
||||||
int MakeNewType();
|
int MakeNewType();
|
||||||
BaseException *FromErrno(const wxString &streamname, int errcode);
|
BaseException* FromErrno(const wxString& streamname, int errcode);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BaseException
|
// BaseException
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
|
// 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
|
// 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.
|
// 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.
|
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||||
// Use Exception::RuntimeError instead for generic exceptions.
|
// Use Exception::RuntimeError instead for generic exceptions.
|
||||||
//
|
//
|
||||||
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
||||||
// this class has only a trivial constructor, and must be manually initialized using
|
// 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
|
// 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.
|
// is, by design, a lot of fail, especially when class initializers are mixed in.
|
||||||
//
|
//
|
||||||
// [TODO] : Add an InnerException component, and Clone() facility.
|
// [TODO] : Add an InnerException component, and Clone() facility.
|
||||||
//
|
//
|
||||||
class BaseException
|
class BaseException
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
||||||
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BaseException() = default;
|
virtual ~BaseException() = default;
|
||||||
|
|
||||||
const wxString &DiagMsg() const { return m_message_diag; }
|
const wxString& DiagMsg() const { return m_message_diag; }
|
||||||
const wxString &UserMsg() const { return m_message_user; }
|
const wxString& UserMsg() const { return m_message_user; }
|
||||||
|
|
||||||
wxString &DiagMsg() { return m_message_diag; }
|
wxString& DiagMsg() { return m_message_diag; }
|
||||||
wxString &UserMsg() { return m_message_user; }
|
wxString& UserMsg() { return m_message_user; }
|
||||||
|
|
||||||
BaseException &SetBothMsgs(const wxChar *msg_diag);
|
BaseException& SetBothMsgs(const wxChar* msg_diag);
|
||||||
BaseException &SetDiagMsg(const wxString &msg_diag);
|
BaseException& SetDiagMsg(const wxString& msg_diag);
|
||||||
BaseException &SetUserMsg(const wxString &msg_user);
|
BaseException& SetUserMsg(const wxString& msg_user);
|
||||||
|
|
||||||
// Returns a message suitable for diagnostic / logging purposes.
|
// Returns a message suitable for diagnostic / logging purposes.
|
||||||
// This message is always in English, and includes a full stack trace.
|
// This message is always in English, and includes a full stack trace.
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
|
|
||||||
// Returns a message suitable for end-user display.
|
// Returns a message suitable for end-user display.
|
||||||
// This message is usually meant for display in a user popup or such.
|
// This message is usually meant for display in a user popup or such.
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
|
|
||||||
virtual void Rethrow() const = 0;
|
virtual void Rethrow() const = 0;
|
||||||
virtual BaseException *Clone() const = 0;
|
virtual BaseException* Clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unique_ptr<BaseException> ScopedExcept;
|
typedef std::unique_ptr<BaseException> ScopedExcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Ps2Generic Exception
|
// Ps2Generic Exception
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||||
//
|
//
|
||||||
// Implementation note: does not derive from BaseException, so that we can use different
|
// Implementation note: does not derive from BaseException, so that we can use different
|
||||||
// catch block hierarchies to handle them (if needed).
|
// catch block hierarchies to handle them (if needed).
|
||||||
//
|
//
|
||||||
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
||||||
// format only. :)
|
// format only. :)
|
||||||
//
|
//
|
||||||
class Ps2Generic
|
class Ps2Generic
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
|
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Ps2Generic() = default;
|
virtual ~Ps2Generic() = default;
|
||||||
|
|
||||||
virtual u32 GetPc() const = 0;
|
virtual u32 GetPc() const = 0;
|
||||||
virtual bool IsDelaySlot() const = 0;
|
virtual bool IsDelaySlot() const = 0;
|
||||||
virtual wxString &Message() { return m_message; }
|
virtual wxString& Message() { return m_message; }
|
||||||
|
|
||||||
virtual void Rethrow() const = 0;
|
virtual void Rethrow() const = 0;
|
||||||
virtual Ps2Generic *Clone() const = 0;
|
virtual Ps2Generic* Clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||||
// Parameters:
|
// Parameters:
|
||||||
|
@ -157,240 +163,254 @@ public:
|
||||||
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
||||||
//
|
//
|
||||||
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||||
private: \
|
private: \
|
||||||
typedef parent _parent; \
|
typedef parent _parent; \
|
||||||
\
|
\
|
||||||
public: \
|
public: \
|
||||||
virtual ~classname() = default; \
|
virtual ~classname() = default; \
|
||||||
virtual void Rethrow() const { throw * this; } \
|
\
|
||||||
virtual classname *Clone() const { return new classname(*this); }
|
virtual void Rethrow() const \
|
||||||
|
{ \
|
||||||
|
throw *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
virtual classname* Clone() const \
|
||||||
|
{ \
|
||||||
|
return new classname(*this); \
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
||||||
public: \
|
public: \
|
||||||
classname &SetBothMsgs(const wxChar *msg_diag) \
|
classname& SetBothMsgs(const wxChar* msg_diag) \
|
||||||
{ \
|
{ \
|
||||||
BaseException::SetBothMsgs(msg_diag); \
|
BaseException::SetBothMsgs(msg_diag); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
classname &SetDiagMsg(const wxString &msg_diag) \
|
\
|
||||||
{ \
|
classname& SetDiagMsg(const wxString& msg_diag) \
|
||||||
m_message_diag = msg_diag; \
|
{ \
|
||||||
return *this; \
|
m_message_diag = msg_diag; \
|
||||||
} \
|
return *this; \
|
||||||
classname &SetUserMsg(const wxString &msg_user) \
|
} \
|
||||||
{ \
|
\
|
||||||
m_message_user = msg_user; \
|
classname& SetUserMsg(const wxString& msg_user) \
|
||||||
return *this; \
|
{ \
|
||||||
}
|
m_message_user = msg_user; \
|
||||||
|
return *this; \
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
||||||
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||||
classname() { SetDiagMsg(message); } \
|
classname() \
|
||||||
DEFINE_EXCEPTION_MESSAGES(classname)
|
{ \
|
||||||
|
SetDiagMsg(message); \
|
||||||
|
} \
|
||||||
|
DEFINE_EXCEPTION_MESSAGES(classname)
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class RuntimeError : public BaseException
|
class RuntimeError : public BaseException
|
||||||
{
|
{
|
||||||
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
|
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
|
||||||
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
|
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool IsSilent;
|
bool IsSilent;
|
||||||
|
|
||||||
RuntimeError() { IsSilent = false; }
|
RuntimeError() { IsSilent = false; }
|
||||||
RuntimeError(const std::runtime_error &ex, const wxString &prefix = wxEmptyString);
|
RuntimeError(const std::runtime_error& ex, const wxString& prefix = wxEmptyString);
|
||||||
RuntimeError(const std::exception &ex, const wxString &prefix = wxEmptyString);
|
RuntimeError(const std::exception& ex, const wxString& prefix = wxEmptyString);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
|
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
|
||||||
// instead issues a "silent" cancelation that is handled by the app gracefully (generates
|
// instead issues a "silent" cancelation that is handled by the app gracefully (generates
|
||||||
// log, and resumes messages queue processing).
|
// log, and resumes messages queue processing).
|
||||||
//
|
//
|
||||||
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
|
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
|
||||||
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
|
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
|
||||||
class CancelEvent : public RuntimeError
|
class CancelEvent : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given."))
|
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given."))
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CancelEvent(const wxString &logmsg)
|
explicit CancelEvent(const wxString& logmsg)
|
||||||
{
|
{
|
||||||
m_message_diag = logmsg;
|
m_message_diag = logmsg;
|
||||||
// overridden message formatters only use the diagnostic version...
|
// overridden message formatters only use the diagnostic version...
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// OutOfMemory
|
// OutOfMemory
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
|
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
|
||||||
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
|
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
|
||||||
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
|
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
|
||||||
// where %s is filled in with the block name.
|
// where %s is filled in with the block name.
|
||||||
//
|
//
|
||||||
// The user string is not custom-formatted, and should contain *NO* %s tags.
|
// The user string is not custom-formatted, and should contain *NO* %s tags.
|
||||||
//
|
//
|
||||||
class OutOfMemory : public RuntimeError
|
class OutOfMemory : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString)
|
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxString AllocDescription;
|
wxString AllocDescription;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OutOfMemory(const wxString &allocdesc);
|
OutOfMemory(const wxString& allocdesc);
|
||||||
|
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParseError : public RuntimeError
|
class ParseError : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
|
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// Hardware/OS Exceptions:
|
// Hardware/OS Exceptions:
|
||||||
// HardwareDeficiency / VirtualMemoryMapConflict
|
// HardwareDeficiency / VirtualMemoryMapConflict
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// This exception is a specific type of OutOfMemory error that isn't "really" an out of
|
// This exception is a specific type of OutOfMemory error that isn't "really" an out of
|
||||||
// memory error. More likely it's caused by a plugin or driver reserving a range of memory
|
// memory error. More likely it's caused by a plugin or driver reserving a range of memory
|
||||||
// we'd really like to have access to.
|
// we'd really like to have access to.
|
||||||
class VirtualMemoryMapConflict : public OutOfMemory
|
class VirtualMemoryMapConflict : public OutOfMemory
|
||||||
{
|
{
|
||||||
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString)
|
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString)
|
||||||
|
|
||||||
VirtualMemoryMapConflict(const wxString &allocdesc);
|
VirtualMemoryMapConflict(const wxString& allocdesc);
|
||||||
|
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HardwareDeficiency : public RuntimeError
|
class HardwareDeficiency : public RuntimeError
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
|
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// Streaming (file) Exceptions:
|
// Streaming (file) Exceptions:
|
||||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
|
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
|
||||||
virtual classname &SetStreamName(const wxString &name) \
|
virtual classname& SetStreamName(const wxString& name) \
|
||||||
{ \
|
{ \
|
||||||
StreamName = name; \
|
StreamName = name; \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
virtual classname &SetStreamName(const char *name) \
|
\
|
||||||
{ \
|
virtual classname& SetStreamName(const char* name) \
|
||||||
StreamName = fromUTF8(name); \
|
{ \
|
||||||
return *this; \
|
StreamName = fromUTF8(name); \
|
||||||
}
|
return *this; \
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
|
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
|
||||||
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
|
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
|
||||||
classname(const wxString &filename) \
|
classname(const wxString& filename) \
|
||||||
{ \
|
{ \
|
||||||
StreamName = filename; \
|
StreamName = filename; \
|
||||||
} \
|
} \
|
||||||
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
|
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
|
||||||
|
|
||||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
// 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
|
// connection, or anything else that would indicate a failure to open a stream or read the
|
||||||
// data after the stream was successfully opened.
|
// data after the stream was successfully opened.
|
||||||
//
|
//
|
||||||
class BadStream : public RuntimeError
|
class BadStream : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
|
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxString StreamName; // name of the stream (if applicable)
|
wxString StreamName; // name of the stream (if applicable)
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _formatDiagMsg(FastFormatUnicode &dest) const;
|
void _formatDiagMsg(FastFormatUnicode& dest) const;
|
||||||
void _formatUserMsg(FastFormatUnicode &dest) const;
|
void _formatUserMsg(FastFormatUnicode& dest) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A generic exception for odd-ball stream creation errors.
|
// A generic exception for odd-ball stream creation errors.
|
||||||
//
|
//
|
||||||
class CannotCreateStream : public BadStream
|
class CannotCreateStream : public BadStream
|
||||||
{
|
{
|
||||||
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
|
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Exception thrown when an attempt to open a non-existent file is made.
|
// Exception thrown when an attempt to open a non-existent file is made.
|
||||||
// (this exception can also mean file permissions are invalid)
|
// (this exception can also mean file permissions are invalid)
|
||||||
//
|
//
|
||||||
class FileNotFound : public CannotCreateStream
|
class FileNotFound : public CannotCreateStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
|
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AccessDenied : public CannotCreateStream
|
class AccessDenied : public CannotCreateStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
|
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||||
// feof checks.
|
// feof checks.
|
||||||
//
|
//
|
||||||
class EndOfStream : public BadStream
|
class EndOfStream : public BadStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
|
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Exception::WinApiError
|
// Exception::WinApiError
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class WinApiError : public RuntimeError
|
class WinApiError : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
||||||
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int ErrorId;
|
int ErrorId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WinApiError();
|
WinApiError();
|
||||||
|
|
||||||
wxString GetMsgFromWindows() const;
|
wxString GetMsgFromWindows() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace Exception
|
||||||
|
|
||||||
using Exception::BaseException;
|
using Exception::BaseException;
|
||||||
using Exception::ScopedExcept;
|
using Exception::ScopedExcept;
|
||||||
|
|
|
@ -33,88 +33,88 @@ template class SafeAlignedArray<u8, 16>;
|
||||||
// system deadlock.
|
// system deadlock.
|
||||||
static const int MaxFormattedStringLength = 0x80000;
|
static const int MaxFormattedStringLength = 0x80000;
|
||||||
|
|
||||||
static
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
__ri
|
static __ri void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||||
|
#else
|
||||||
|
static void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||||
#endif
|
#endif
|
||||||
void
|
|
||||||
format_that_ascii_mess(CharBufferType &buffer, uint writepos, const char *fmt, va_list argptr)
|
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
while (true) {
|
while (true)
|
||||||
int size = buffer.GetLength();
|
{
|
||||||
|
int size = buffer.GetLength();
|
||||||
|
|
||||||
va_copy(args, argptr);
|
va_copy(args, argptr);
|
||||||
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
|
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// some implementations of vsnprintf() don't NUL terminate
|
// some implementations of vsnprintf() don't NUL terminate
|
||||||
// the string if there is not enough space for it so
|
// the string if there is not enough space for it so
|
||||||
// always do it manually
|
// always do it manually
|
||||||
buffer[size - 1] = '\0';
|
buffer[size - 1] = '\0';
|
||||||
|
|
||||||
if (size >= MaxFormattedStringLength)
|
if (size >= MaxFormattedStringLength)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||||
// total number of characters which would have been written if the
|
// total number of characters which would have been written if the
|
||||||
// buffer were large enough (newer standards such as Unix98)
|
// buffer were large enough (newer standards such as Unix98)
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = size + (size / 4);
|
len = size + (size / 4);
|
||||||
|
|
||||||
len += writepos;
|
len += writepos;
|
||||||
if (len < size)
|
if (len < size)
|
||||||
break;
|
break;
|
||||||
buffer.Resize(len + 128);
|
buffer.Resize(len + 128);
|
||||||
};
|
};
|
||||||
|
|
||||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||||
// though it'd be kinda nice if we did.
|
// though it'd be kinda nice if we did.
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the length of the formatted string, in characters (wxChars).
|
// returns the length of the formatted string, in characters (wxChars).
|
||||||
static
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
__ri
|
static __ri uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||||
|
#else
|
||||||
|
static uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||||
#endif
|
#endif
|
||||||
uint
|
|
||||||
format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr)
|
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
while (true) {
|
while (true)
|
||||||
int size = buffer.GetLength() / sizeof(wxChar);
|
{
|
||||||
|
int size = buffer.GetLength() / sizeof(wxChar);
|
||||||
|
|
||||||
va_copy(args, argptr);
|
va_copy(args, argptr);
|
||||||
int len = wxVsnprintf((wxChar *)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
|
int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// some implementations of vsnprintf() don't NUL terminate
|
// some implementations of vsnprintf() don't NUL terminate
|
||||||
// the string if there is not enough space for it so
|
// the string if there is not enough space for it so
|
||||||
// always do it manually
|
// always do it manually
|
||||||
((wxChar *)buffer.GetPtr())[size - 1] = L'\0';
|
((wxChar*)buffer.GetPtr())[size - 1] = L'\0';
|
||||||
|
|
||||||
if (size >= MaxFormattedStringLength)
|
if (size >= MaxFormattedStringLength)
|
||||||
return size - 1;
|
return size - 1;
|
||||||
|
|
||||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||||
// total number of characters which would have been written if the
|
// total number of characters which would have been written if the
|
||||||
// buffer were large enough (newer standards such as Unix98)
|
// buffer were large enough (newer standards such as Unix98)
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = size + (size / 4);
|
len = size + (size / 4);
|
||||||
|
|
||||||
len += writepos;
|
len += writepos;
|
||||||
if (len < size)
|
if (len < size)
|
||||||
return len;
|
return len;
|
||||||
buffer.Resize((len + 128) * sizeof(wxChar));
|
buffer.Resize((len + 128) * sizeof(wxChar));
|
||||||
};
|
};
|
||||||
|
|
||||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||||
// though it'd be kinda nice if we did.
|
// though it'd be kinda nice if we did.
|
||||||
|
|
||||||
pxAssume(false);
|
pxAssume(false);
|
||||||
return 0; // unreachable.
|
return 0; // unreachable.
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -127,124 +127,124 @@ static
|
||||||
// this class nicely in its current state. --air
|
// this class nicely in its current state. --air
|
||||||
|
|
||||||
FastFormatUnicode::FastFormatUnicode()
|
FastFormatUnicode::FastFormatUnicode()
|
||||||
: m_dest(2048)
|
: m_dest(2048)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFormatUnicode::Clear()
|
void FastFormatUnicode::Clear()
|
||||||
{
|
{
|
||||||
m_Length = 0;
|
m_Length = 0;
|
||||||
((wxChar *)m_dest.GetPtr())[0] = 0;
|
((wxChar*)m_dest.GetPtr())[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::WriteV(const char *fmt, va_list argptr)
|
FastFormatUnicode& FastFormatUnicode::WriteV(const char* fmt, va_list argptr)
|
||||||
{
|
{
|
||||||
wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr)));
|
wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr)));
|
||||||
|
|
||||||
const uint inspos = m_Length;
|
const uint inspos = m_Length;
|
||||||
const uint convLen = converted.Length();
|
const uint convLen = converted.Length();
|
||||||
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
|
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
|
||||||
memcpy(&((wxChar *)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
|
memcpy(&((wxChar*)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
|
||||||
m_Length += convLen;
|
m_Length += convLen;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::WriteV(const wxChar *fmt, va_list argptr)
|
FastFormatUnicode& FastFormatUnicode::WriteV(const wxChar* fmt, va_list argptr)
|
||||||
{
|
{
|
||||||
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
|
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::Write(const char *fmt, ...)
|
FastFormatUnicode& FastFormatUnicode::Write(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::Write(const wxChar *fmt, ...)
|
FastFormatUnicode& FastFormatUnicode::Write(const wxChar* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::Write(const wxString fmt, ...)
|
FastFormatUnicode& FastFormatUnicode::Write(const wxString fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt.wx_str(), list);
|
WriteV(fmt.wx_str(), list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FastFormatUnicode::IsEmpty() const
|
bool FastFormatUnicode::IsEmpty() const
|
||||||
{
|
{
|
||||||
return ((wxChar &)m_dest[0]) == 0;
|
return ((wxChar&)m_dest[0]) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::ToUpper()
|
FastFormatUnicode& FastFormatUnicode::ToUpper()
|
||||||
{
|
{
|
||||||
wxChar *ch = (wxChar *)m_dest.GetPtr();
|
wxChar* ch = (wxChar*)m_dest.GetPtr();
|
||||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||||
*ch = (wxChar)wxToupper(*ch);
|
*ch = (wxChar)wxToupper(*ch);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::ToLower()
|
FastFormatUnicode& FastFormatUnicode::ToLower()
|
||||||
{
|
{
|
||||||
wxChar *ch = (wxChar *)m_dest.GetPtr();
|
wxChar* ch = (wxChar*)m_dest.GetPtr();
|
||||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||||
*ch = (wxChar)wxTolower(*ch);
|
*ch = (wxChar)wxTolower(*ch);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &FastFormatUnicode::operator+=(const char *psz)
|
FastFormatUnicode& FastFormatUnicode::operator+=(const char* psz)
|
||||||
{
|
{
|
||||||
Write(L"%s", WX_STR(fromUTF8(psz)));
|
Write(L"%s", WX_STR(fromUTF8(psz)));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString &operator+=(wxString &str1, const FastFormatUnicode &str2)
|
wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
|
||||||
{
|
{
|
||||||
str1.Append(str2.c_str(), str2.Length());
|
str1.Append(str2.c_str(), str2.Length());
|
||||||
return str1;
|
return str1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString operator+(const wxString &str1, const FastFormatUnicode &str2)
|
wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
|
||||||
{
|
{
|
||||||
wxString s = str1;
|
wxString s = str1;
|
||||||
s += str2;
|
s += str2;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString operator+(const wxChar *str1, const FastFormatUnicode &str2)
|
wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
|
||||||
{
|
{
|
||||||
wxString s = str1;
|
wxString s = str1;
|
||||||
s += str2;
|
s += str2;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString operator+(const FastFormatUnicode &str1, const wxString &str2)
|
wxString operator+(const FastFormatUnicode& str1, const wxString& str2)
|
||||||
{
|
{
|
||||||
wxString s = str1;
|
wxString s = str1;
|
||||||
s += str2;
|
s += str2;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
|
wxString operator+(const FastFormatUnicode& str1, const wxChar* str2)
|
||||||
{
|
{
|
||||||
wxString s = str1;
|
wxString s = str1;
|
||||||
s += str2;
|
s += str2;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,38 +252,38 @@ wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
|
||||||
// FastFormatAscii (implementations)
|
// FastFormatAscii (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
FastFormatAscii::FastFormatAscii()
|
FastFormatAscii::FastFormatAscii()
|
||||||
: m_dest(2048)
|
: m_dest(2048)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFormatAscii::Clear()
|
void FastFormatAscii::Clear()
|
||||||
{
|
{
|
||||||
m_dest.GetPtr()[0] = 0;
|
m_dest.GetPtr()[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxString FastFormatAscii::GetString() const
|
const wxString FastFormatAscii::GetString() const
|
||||||
{
|
{
|
||||||
return fromAscii(m_dest.GetPtr());
|
return fromAscii(m_dest.GetPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatAscii &FastFormatAscii::WriteV(const char *fmt, va_list argptr)
|
FastFormatAscii& FastFormatAscii::WriteV(const char* fmt, va_list argptr)
|
||||||
{
|
{
|
||||||
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
|
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatAscii &FastFormatAscii::Write(const char *fmt, ...)
|
FastFormatAscii& FastFormatAscii::Write(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FastFormatAscii::IsEmpty() const
|
bool FastFormatAscii::IsEmpty() const
|
||||||
{
|
{
|
||||||
return m_dest[0] == 0;
|
return m_dest[0] == 0;
|
||||||
}
|
}
|
||||||
|
|
204
common/General.h
204
common/General.h
|
@ -26,17 +26,15 @@
|
||||||
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
||||||
//
|
//
|
||||||
#define BITFIELD32() \
|
#define BITFIELD32() \
|
||||||
union \
|
union \
|
||||||
{ \
|
{ \
|
||||||
u32 bitset; \
|
u32 bitset; \
|
||||||
struct \
|
struct \
|
||||||
{
|
{
|
||||||
|
|
||||||
#define BITFIELD_END \
|
#define BITFIELD_END \
|
||||||
} \
|
}; \
|
||||||
; \
|
};
|
||||||
} \
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
@ -52,20 +50,20 @@
|
||||||
class RecursionGuard
|
class RecursionGuard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int &Counter;
|
int& Counter;
|
||||||
|
|
||||||
RecursionGuard(int &counter)
|
RecursionGuard(int& counter)
|
||||||
: Counter(counter)
|
: Counter(counter)
|
||||||
{
|
{
|
||||||
++Counter;
|
++Counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RecursionGuard()
|
virtual ~RecursionGuard()
|
||||||
{
|
{
|
||||||
--Counter;
|
--Counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsReentrant() const { return Counter > 1; }
|
bool IsReentrant() const { return Counter > 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -74,30 +72,30 @@ public:
|
||||||
class IActionInvocation
|
class IActionInvocation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IActionInvocation() = default;
|
virtual ~IActionInvocation() = default;
|
||||||
virtual void InvokeAction() = 0;
|
virtual void InvokeAction() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICloneable
|
class ICloneable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ICloneable *Clone() const = 0;
|
virtual ICloneable* Clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IDeletableObject
|
class IDeletableObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IDeletableObject() = default;
|
virtual ~IDeletableObject() = default;
|
||||||
|
|
||||||
virtual void DeleteSelf() = 0;
|
virtual void DeleteSelf() = 0;
|
||||||
virtual bool IsBeingDeleted() = 0;
|
virtual bool IsBeingDeleted() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||||
// need to implement one yourself (yay?).
|
// need to implement one yourself (yay?).
|
||||||
virtual void DoDeletion() = 0;
|
virtual void DoDeletion() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -126,26 +124,26 @@ protected:
|
||||||
class BaseDeletableObject : public virtual IDeletableObject
|
class BaseDeletableObject : public virtual IDeletableObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::atomic<bool> m_IsBeingDeleted;
|
std::atomic<bool> m_IsBeingDeleted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseDeletableObject();
|
BaseDeletableObject();
|
||||||
virtual ~BaseDeletableObject();
|
virtual ~BaseDeletableObject();
|
||||||
|
|
||||||
void DeleteSelf();
|
void DeleteSelf();
|
||||||
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
|
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
|
||||||
|
|
||||||
// Returns FALSE if the object is already marked for deletion, or TRUE if the app
|
// Returns FALSE if the object is already marked for deletion, or TRUE if the app
|
||||||
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
|
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
|
||||||
// the object could get deleted twice if two threads try to schedule it at the same time.
|
// the object could get deleted twice if two threads try to schedule it at the same time.
|
||||||
bool MarkForDeletion();
|
bool MarkForDeletion();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||||
// need to implement one yourself (yay?).
|
// need to implement one yourself (yay?).
|
||||||
virtual void DoDeletion();
|
virtual void DoDeletion();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -154,76 +152,76 @@ protected:
|
||||||
class PageProtectionMode
|
class PageProtectionMode
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool m_read;
|
bool m_read;
|
||||||
bool m_write;
|
bool m_write;
|
||||||
bool m_exec;
|
bool m_exec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageProtectionMode()
|
PageProtectionMode()
|
||||||
{
|
{
|
||||||
All(false);
|
All(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
PageProtectionMode &Read(bool allow = true)
|
PageProtectionMode& Read(bool allow = true)
|
||||||
{
|
{
|
||||||
m_read = allow;
|
m_read = allow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PageProtectionMode &Write(bool allow = true)
|
PageProtectionMode& Write(bool allow = true)
|
||||||
{
|
{
|
||||||
m_write = allow;
|
m_write = allow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PageProtectionMode &Execute(bool allow = true)
|
PageProtectionMode& Execute(bool allow = true)
|
||||||
{
|
{
|
||||||
m_exec = allow;
|
m_exec = allow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PageProtectionMode &All(bool allow = true)
|
PageProtectionMode& All(bool allow = true)
|
||||||
{
|
{
|
||||||
m_read = m_write = m_exec = allow;
|
m_read = m_write = m_exec = allow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanRead() const { return m_read; }
|
bool CanRead() const { return m_read; }
|
||||||
bool CanWrite() const { return m_write; }
|
bool CanWrite() const { return m_write; }
|
||||||
bool CanExecute() const { return m_exec && m_read; }
|
bool CanExecute() const { return m_exec && m_read; }
|
||||||
bool IsNone() const { return !m_read && !m_write; }
|
bool IsNone() const { return !m_read && !m_write; }
|
||||||
|
|
||||||
wxString ToString() const;
|
wxString ToString() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_None()
|
static __fi PageProtectionMode PageAccess_None()
|
||||||
{
|
{
|
||||||
return PageProtectionMode();
|
return PageProtectionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_ReadOnly()
|
static __fi PageProtectionMode PageAccess_ReadOnly()
|
||||||
{
|
{
|
||||||
return PageProtectionMode().Read();
|
return PageProtectionMode().Read();
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_WriteOnly()
|
static __fi PageProtectionMode PageAccess_WriteOnly()
|
||||||
{
|
{
|
||||||
return PageProtectionMode().Write();
|
return PageProtectionMode().Write();
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_ReadWrite()
|
static __fi PageProtectionMode PageAccess_ReadWrite()
|
||||||
{
|
{
|
||||||
return PageAccess_ReadOnly().Write();
|
return PageAccess_ReadOnly().Write();
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_ExecOnly()
|
static __fi PageProtectionMode PageAccess_ExecOnly()
|
||||||
{
|
{
|
||||||
return PageAccess_ReadOnly().Execute();
|
return PageAccess_ReadOnly().Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fi PageProtectionMode PageAccess_Any()
|
static __fi PageProtectionMode PageAccess_Any()
|
||||||
{
|
{
|
||||||
return PageProtectionMode().All();
|
return PageProtectionMode().All();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -233,35 +231,35 @@ static __fi PageProtectionMode PageAccess_Any()
|
||||||
// platform prior to wxWidgets .. it should prolly be removed -- air)
|
// platform prior to wxWidgets .. it should prolly be removed -- air)
|
||||||
namespace HostSys
|
namespace HostSys
|
||||||
{
|
{
|
||||||
void *MmapReserve(uptr base, size_t size);
|
void* MmapReserve(uptr base, size_t size);
|
||||||
bool MmapCommit(uptr base, size_t size, const PageProtectionMode &mode);
|
bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
|
||||||
void MmapReset(uptr base, size_t size);
|
void MmapReset(uptr base, size_t size);
|
||||||
|
|
||||||
void *MmapReservePtr(void *base, size_t size);
|
void* MmapReservePtr(void* base, size_t size);
|
||||||
bool MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode);
|
bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
|
||||||
void MmapResetPtr(void *base, size_t size);
|
void MmapResetPtr(void* base, size_t size);
|
||||||
|
|
||||||
// Maps a block of memory for use as a recompiled code buffer.
|
// Maps a block of memory for use as a recompiled code buffer.
|
||||||
// Returns NULL on allocation failure.
|
// Returns NULL on allocation failure.
|
||||||
extern void *Mmap(uptr base, size_t size);
|
extern void* Mmap(uptr base, size_t size);
|
||||||
|
|
||||||
// Unmaps a block allocated by SysMmap
|
// Unmaps a block allocated by SysMmap
|
||||||
extern void Munmap(uptr base, size_t size);
|
extern void Munmap(uptr base, size_t size);
|
||||||
|
|
||||||
extern void MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode);
|
extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
|
||||||
|
|
||||||
extern void Munmap(void *base, size_t size);
|
extern void Munmap(void* base, size_t size);
|
||||||
|
|
||||||
template <uint size>
|
template <uint size>
|
||||||
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode &mode)
|
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
MemProtect(arr, size, mode);
|
MemProtect(arr, size, mode);
|
||||||
}
|
}
|
||||||
}
|
} // namespace HostSys
|
||||||
|
|
||||||
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
||||||
#define SafeSysMunmap(ptr, size) \
|
#define SafeSysMunmap(ptr, size) \
|
||||||
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
|
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
|
||||||
|
|
||||||
extern void InitCPUTicks();
|
extern void InitCPUTicks();
|
||||||
extern u64 GetTickFrequency();
|
extern u64 GetTickFrequency();
|
||||||
|
|
|
@ -23,393 +23,404 @@ const wxRect wxDefaultRect(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDef
|
||||||
wxDirName g_fullBaseDirName = wxDirName(L"");
|
wxDirName g_fullBaseDirName = wxDirName(L"");
|
||||||
void SetFullBaseDir(wxDirName appRoot)
|
void SetFullBaseDir(wxDirName appRoot)
|
||||||
{
|
{
|
||||||
g_fullBaseDirName = appRoot;
|
g_fullBaseDirName = appRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _calcEnumLength(const wxChar *const *enumArray)
|
static int _calcEnumLength(const wxChar* const* enumArray)
|
||||||
{
|
{
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
while (*enumArray != NULL) {
|
while (*enumArray != NULL)
|
||||||
enumArray++;
|
{
|
||||||
cnt++;
|
enumArray++;
|
||||||
}
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedIniGroup::ScopedIniGroup(IniInterface &mommy, const wxString &group)
|
ScopedIniGroup::ScopedIniGroup(IniInterface& mommy, const wxString& group)
|
||||||
: m_mom(mommy)
|
: m_mom(mommy)
|
||||||
{
|
{
|
||||||
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
|
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
|
||||||
m_mom.SetPath(group);
|
m_mom.SetPath(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedIniGroup::~ScopedIniGroup()
|
ScopedIniGroup::~ScopedIniGroup()
|
||||||
{
|
{
|
||||||
m_mom.SetPath(L"..");
|
m_mom.SetPath(L"..");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// IniInterface (implementations)
|
// IniInterface (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
IniInterface::IniInterface(wxConfigBase &config)
|
IniInterface::IniInterface(wxConfigBase& config)
|
||||||
{
|
{
|
||||||
m_Config = &config;
|
m_Config = &config;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniInterface::IniInterface(wxConfigBase *config)
|
IniInterface::IniInterface(wxConfigBase* config)
|
||||||
{
|
{
|
||||||
m_Config = config;
|
m_Config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniInterface::IniInterface()
|
IniInterface::IniInterface()
|
||||||
{
|
{
|
||||||
m_Config = wxConfigBase::Get(false);
|
m_Config = wxConfigBase::Get(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniInterface::~IniInterface()
|
IniInterface::~IniInterface()
|
||||||
{
|
{
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniInterface::SetPath(const wxString &path)
|
void IniInterface::SetPath(const wxString& path)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->SetPath(path);
|
m_Config->SetPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniInterface::Flush()
|
void IniInterface::Flush()
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Flush();
|
m_Config->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// IniLoader (implementations)
|
// IniLoader (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
IniLoader::IniLoader(wxConfigBase &config)
|
IniLoader::IniLoader(wxConfigBase& config)
|
||||||
: IniInterface(config)
|
: IniInterface(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IniLoader::IniLoader(wxConfigBase *config)
|
IniLoader::IniLoader(wxConfigBase* config)
|
||||||
: IniInterface(config)
|
: IniInterface(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IniLoader::IniLoader()
|
IniLoader::IniLoader()
|
||||||
: IniInterface()
|
: IniInterface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxString &value, const wxString defvalue)
|
void IniLoader::Entry(const wxString& var, wxString& value, const wxString defvalue)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &value, defvalue);
|
m_Config->Read(var, &value, defvalue);
|
||||||
else
|
else
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
|
void IniLoader::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
|
||||||
{
|
{
|
||||||
wxString dest;
|
wxString dest;
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &dest, wxEmptyString);
|
m_Config->Read(var, &dest, wxEmptyString);
|
||||||
|
|
||||||
if (dest.IsEmpty())
|
if (dest.IsEmpty())
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
else {
|
else
|
||||||
value = dest;
|
{
|
||||||
if (isAllowRelative)
|
value = dest;
|
||||||
value = g_fullBaseDirName + value;
|
if (isAllowRelative)
|
||||||
|
value = g_fullBaseDirName + value;
|
||||||
|
|
||||||
if (value.IsAbsolute())
|
if (value.IsAbsolute())
|
||||||
value.Normalize();
|
value.Normalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
|
void IniLoader::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
|
||||||
{
|
{
|
||||||
wxString dest(defvalue.GetFullPath());
|
wxString dest(defvalue.GetFullPath());
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &dest, defvalue.GetFullPath());
|
m_Config->Read(var, &dest, defvalue.GetFullPath());
|
||||||
value = dest;
|
value = dest;
|
||||||
if (isAllowRelative)
|
if (isAllowRelative)
|
||||||
value = g_fullBaseDirName + value;
|
value = g_fullBaseDirName + value;
|
||||||
|
|
||||||
if (value.IsAbsolute())
|
if (value.IsAbsolute())
|
||||||
value.Normalize();
|
value.Normalize();
|
||||||
|
|
||||||
if (value.HasVolume())
|
if (value.HasVolume())
|
||||||
value.SetVolume(value.GetVolume().Upper());
|
value.SetVolume(value.GetVolume().Upper());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, int &value, const int defvalue)
|
void IniLoader::Entry(const wxString& var, int& value, const int defvalue)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &value, defvalue);
|
m_Config->Read(var, &value, defvalue);
|
||||||
else
|
else
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, uint &value, const uint defvalue)
|
void IniLoader::Entry(const wxString& var, uint& value, const uint defvalue)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, (int *)&value, (int)defvalue);
|
m_Config->Read(var, (int*)&value, (int)defvalue);
|
||||||
else
|
else
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, bool &value, const bool defvalue)
|
void IniLoader::Entry(const wxString& var, bool& value, const bool defvalue)
|
||||||
{
|
{
|
||||||
// TODO : Stricter value checking on enabled/disabled?
|
// TODO : Stricter value checking on enabled/disabled?
|
||||||
wxString dest;
|
wxString dest;
|
||||||
if(defvalue)
|
if (defvalue)
|
||||||
dest = wxString("enabled");
|
dest = wxString("enabled");
|
||||||
else
|
else
|
||||||
dest = wxString("disabled");
|
dest = wxString("disabled");
|
||||||
|
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &dest, dest);
|
m_Config->Read(var, &dest, dest);
|
||||||
value = (dest == L"enabled") || (dest == L"1");
|
value = (dest == L"enabled") || (dest == L"1");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IniLoader::EntryBitBool(const wxString &var, bool value, const bool defvalue)
|
bool IniLoader::EntryBitBool(const wxString& var, bool value, const bool defvalue)
|
||||||
{
|
{
|
||||||
// Note: 'value' param is used by inisaver only.
|
// Note: 'value' param is used by inisaver only.
|
||||||
bool result;
|
bool result;
|
||||||
Entry(var, result, defvalue);
|
Entry(var, result, defvalue);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IniLoader::EntryBitfield(const wxString &var, int value, const int defvalue)
|
int IniLoader::EntryBitfield(const wxString& var, int value, const int defvalue)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
Entry(var, result, defvalue);
|
Entry(var, result, defvalue);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, double& value, const double defvalue)
|
void IniLoader::Entry(const wxString& var, double& value, const double defvalue)
|
||||||
{
|
{
|
||||||
auto readval = wxString::FromDouble(value);
|
auto readval = wxString::FromDouble(value);
|
||||||
|
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Read(var, &readval);
|
m_Config->Read(var, &readval);
|
||||||
|
|
||||||
if (!readval.ToDouble(&value))
|
if (!readval.ToDouble(&value))
|
||||||
value = 0.0;
|
value = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
|
void IniLoader::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
value = defvalue;
|
{
|
||||||
return;
|
value = defvalue;
|
||||||
}
|
return;
|
||||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
}
|
||||||
|
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
|
void IniLoader::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
value = defvalue;
|
{
|
||||||
return;
|
value = defvalue;
|
||||||
}
|
return;
|
||||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
}
|
||||||
|
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
|
void IniLoader::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
value = defvalue;
|
{
|
||||||
return;
|
value = defvalue;
|
||||||
}
|
return;
|
||||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
}
|
||||||
|
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
|
void IniLoader::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
|
||||||
{
|
{
|
||||||
// Confirm default value sanity...
|
// Confirm default value sanity...
|
||||||
|
|
||||||
const int cnt = _calcEnumLength(enumArray);
|
const int cnt = _calcEnumLength(enumArray);
|
||||||
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) {
|
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt))
|
||||||
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
{
|
||||||
defvalue = cnt - 1;
|
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
||||||
}
|
defvalue = cnt - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Sanity confirmed, proceed with craziness!
|
// Sanity confirmed, proceed with craziness!
|
||||||
|
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
value = defvalue;
|
{
|
||||||
return;
|
value = defvalue;
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wxString retval;
|
wxString retval;
|
||||||
m_Config->Read(var, &retval, enumArray[defvalue]);
|
m_Config->Read(var, &retval, enumArray[defvalue]);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (enumArray[i] == NULL) {
|
if (enumArray[i] == NULL)
|
||||||
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
|
{
|
||||||
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
|
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
|
||||||
value = defvalue;
|
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
|
||||||
} else
|
value = defvalue;
|
||||||
value = i;
|
}
|
||||||
|
else
|
||||||
|
value = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// IniSaver (implementations)
|
// IniSaver (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
IniSaver::IniSaver(wxConfigBase &config)
|
IniSaver::IniSaver(wxConfigBase& config)
|
||||||
: IniInterface(config)
|
: IniInterface(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IniSaver::IniSaver(wxConfigBase *config)
|
IniSaver::IniSaver(wxConfigBase* config)
|
||||||
: IniInterface(config)
|
: IniInterface(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IniSaver::IniSaver()
|
IniSaver::IniSaver()
|
||||||
: IniInterface()
|
: IniInterface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxString &value, const wxString defvalue)
|
void IniSaver::Entry(const wxString& var, wxString& value, const wxString defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, value);
|
m_Config->Write(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
|
void IniSaver::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
wxDirName res(value);
|
wxDirName res(value);
|
||||||
|
|
||||||
if (res.IsAbsolute())
|
if (res.IsAbsolute())
|
||||||
res.Normalize();
|
res.Normalize();
|
||||||
|
|
||||||
if (isAllowRelative)
|
if (isAllowRelative)
|
||||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||||
|
|
||||||
|
|
||||||
/*if( value == defvalue )
|
/*if( value == defvalue )
|
||||||
m_Config->Write( var, wxString() );
|
m_Config->Write( var, wxString() );
|
||||||
else*/
|
else*/
|
||||||
m_Config->Write(var, res.ToString());
|
m_Config->Write(var, res.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
|
void IniSaver::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
wxFileName res(value);
|
wxFileName res(value);
|
||||||
|
|
||||||
if (res.IsAbsolute())
|
if (res.IsAbsolute())
|
||||||
res.Normalize();
|
res.Normalize();
|
||||||
|
|
||||||
if (isAllowRelative)
|
if (isAllowRelative)
|
||||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||||
|
|
||||||
m_Config->Write(var, res.GetFullPath());
|
m_Config->Write(var, res.GetFullPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, int &value, const int defvalue)
|
void IniSaver::Entry(const wxString& var, int& value, const int defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, value);
|
m_Config->Write(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, uint &value, const uint defvalue)
|
void IniSaver::Entry(const wxString& var, uint& value, const uint defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, (int)value);
|
m_Config->Write(var, (int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, bool &value, const bool defvalue)
|
void IniSaver::Entry(const wxString& var, bool& value, const bool defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IniSaver::EntryBitBool(const wxString &var, bool value, const bool defvalue)
|
bool IniSaver::EntryBitBool(const wxString& var, bool value, const bool defvalue)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IniSaver::EntryBitfield(const wxString &var, int value, const int defvalue)
|
int IniSaver::EntryBitfield(const wxString& var, int value, const int defvalue)
|
||||||
{
|
{
|
||||||
if (m_Config)
|
if (m_Config)
|
||||||
m_Config->Write(var, value);
|
m_Config->Write(var, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, double &value, const double defvalue)
|
void IniSaver::Entry(const wxString& var, double& value, const double defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_Config->Write(var, wxString::FromDouble(value));
|
m_Config->Write(var, wxString::FromDouble(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
|
void IniSaver::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, ToString(value));
|
m_Config->Write(var, ToString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
|
void IniSaver::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, ToString(value));
|
m_Config->Write(var, ToString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
|
void IniSaver::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
m_Config->Write(var, ToString(value));
|
m_Config->Write(var, ToString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
|
void IniSaver::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
|
||||||
{
|
{
|
||||||
const int cnt = _calcEnumLength(enumArray);
|
const int cnt = _calcEnumLength(enumArray);
|
||||||
|
|
||||||
// Confirm default value sanity...
|
// Confirm default value sanity...
|
||||||
|
|
||||||
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt)) {
|
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt))
|
||||||
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
{
|
||||||
defvalue = cnt - 1;
|
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
||||||
}
|
defvalue = cnt - 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (value >= cnt) {
|
if (value >= cnt)
|
||||||
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
{
|
||||||
Console.Indent().Warning(
|
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
||||||
L"Illegal Value: %d\n"
|
Console.Indent().Warning(
|
||||||
L"Using Default: %d (%s)\n",
|
L"Illegal Value: %d\n"
|
||||||
value, defvalue, enumArray[defvalue]);
|
L"Using Default: %d (%s)\n",
|
||||||
|
value, defvalue, enumArray[defvalue]);
|
||||||
|
|
||||||
// Cause a debug assertion, since this is a fully recoverable error.
|
// Cause a debug assertion, since this is a fully recoverable error.
|
||||||
pxAssert(value < cnt);
|
pxAssert(value < cnt);
|
||||||
|
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Config->Write(var, enumArray[value]);
|
m_Config->Write(var, enumArray[value]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,58 +31,58 @@
|
||||||
class IniInterface
|
class IniInterface
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxConfigBase *m_Config;
|
wxConfigBase* m_Config;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~IniInterface();
|
virtual ~IniInterface();
|
||||||
explicit IniInterface();
|
explicit IniInterface();
|
||||||
explicit IniInterface(wxConfigBase &config);
|
explicit IniInterface(wxConfigBase& config);
|
||||||
explicit IniInterface(wxConfigBase *config);
|
explicit IniInterface(wxConfigBase* config);
|
||||||
|
|
||||||
void SetPath(const wxString &path);
|
void SetPath(const wxString& path);
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
wxConfigBase &GetConfig()
|
wxConfigBase& GetConfig()
|
||||||
{
|
{
|
||||||
pxAssert(m_Config);
|
pxAssert(m_Config);
|
||||||
return *m_Config;
|
return *m_Config;
|
||||||
}
|
}
|
||||||
bool IsOk() const { return m_Config != NULL; }
|
bool IsOk() const { return m_Config != NULL; }
|
||||||
|
|
||||||
virtual bool IsLoading() const = 0;
|
virtual bool IsLoading() const = 0;
|
||||||
bool IsSaving() const { return !IsLoading(); }
|
bool IsSaving() const { return !IsLoading(); }
|
||||||
|
|
||||||
virtual void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString()) = 0;
|
virtual void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString()) = 0;
|
||||||
virtual void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0;
|
virtual void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0;
|
||||||
virtual void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0;
|
virtual void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0;
|
||||||
virtual void Entry(const wxString &var, int &value, const int defvalue = 0) = 0;
|
virtual void Entry(const wxString& var, int& value, const int defvalue = 0) = 0;
|
||||||
virtual void Entry(const wxString &var, uint &value, const uint defvalue = 0) = 0;
|
virtual void Entry(const wxString& var, uint& value, const uint defvalue = 0) = 0;
|
||||||
virtual void Entry(const wxString &var, bool &value, const bool defvalue = false) = 0;
|
virtual void Entry(const wxString& var, bool& value, const bool defvalue = false) = 0;
|
||||||
|
|
||||||
// This special form of Entry is provided for bitfields, which cannot be passed by reference.
|
// This special form of Entry is provided for bitfields, which cannot be passed by reference.
|
||||||
virtual bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false) = 0;
|
virtual bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false) = 0;
|
||||||
virtual int EntryBitfield(const wxString &var, int value, const int defvalue = 0) = 0;
|
virtual int EntryBitfield(const wxString& var, int value, const int defvalue = 0) = 0;
|
||||||
|
|
||||||
virtual void Entry(const wxString &var, double& value, const double defvalue = 0.0) = 0;
|
virtual void Entry(const wxString& var, double& value, const double defvalue = 0.0) = 0;
|
||||||
|
|
||||||
virtual void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition) = 0;
|
virtual void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition) = 0;
|
||||||
virtual void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize) = 0;
|
virtual void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize) = 0;
|
||||||
virtual void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect) = 0;
|
virtual void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect) = 0;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void EnumEntry(const wxString &var, T &value, const wxChar *const *enumArray = NULL, const T defvalue = (T)0)
|
void EnumEntry(const wxString& var, T& value, const wxChar* const* enumArray = NULL, const T defvalue = (T)0)
|
||||||
{
|
{
|
||||||
int tstore = (int)value;
|
int tstore = (int)value;
|
||||||
auto defaultvalue = enum_cast(defvalue);
|
auto defaultvalue = enum_cast(defvalue);
|
||||||
if (enumArray == NULL)
|
if (enumArray == NULL)
|
||||||
Entry(var, tstore, defaultvalue);
|
Entry(var, tstore, defaultvalue);
|
||||||
else
|
else
|
||||||
_EnumEntry(var, tstore, enumArray, defaultvalue);
|
_EnumEntry(var, tstore, enumArray, defaultvalue);
|
||||||
value = (T)tstore;
|
value = (T)tstore;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue) = 0;
|
virtual void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -91,11 +91,11 @@ protected:
|
||||||
class ScopedIniGroup
|
class ScopedIniGroup
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
IniInterface &m_mom;
|
IniInterface& m_mom;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedIniGroup(IniInterface &mommy, const wxString &group);
|
ScopedIniGroup(IniInterface& mommy, const wxString& group);
|
||||||
virtual ~ScopedIniGroup();
|
virtual ~ScopedIniGroup();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -109,31 +109,31 @@ public:
|
||||||
class IniLoader : public IniInterface
|
class IniLoader : public IniInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IniLoader() = default;
|
virtual ~IniLoader() = default;
|
||||||
explicit IniLoader();
|
explicit IniLoader();
|
||||||
explicit IniLoader(wxConfigBase &config);
|
explicit IniLoader(wxConfigBase& config);
|
||||||
explicit IniLoader(wxConfigBase *config);
|
explicit IniLoader(wxConfigBase* config);
|
||||||
|
|
||||||
bool IsLoading() const { return true; }
|
bool IsLoading() const { return true; }
|
||||||
|
|
||||||
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxEmptyString);
|
void Entry(const wxString& var, wxString& value, const wxString defvalue = wxEmptyString);
|
||||||
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||||
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||||
void Entry(const wxString &var, int &value, const int defvalue = 0);
|
void Entry(const wxString& var, int& value, const int defvalue = 0);
|
||||||
void Entry(const wxString &var, uint &value, const uint defvalue = 0);
|
void Entry(const wxString& var, uint& value, const uint defvalue = 0);
|
||||||
void Entry(const wxString &var, bool &value, const bool defvalue = false);
|
void Entry(const wxString& var, bool& value, const bool defvalue = false);
|
||||||
|
|
||||||
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false);
|
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
|
||||||
int EntryBitfield(const wxString &var, int value, const int defvalue = 0);
|
int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
|
||||||
|
|
||||||
void Entry(const wxString &var, double& value, const double defvalue = 0.0) override;
|
void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
|
||||||
|
|
||||||
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition);
|
void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
|
||||||
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize);
|
void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
|
||||||
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
|
void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue);
|
void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -147,31 +147,31 @@ protected:
|
||||||
class IniSaver : public IniInterface
|
class IniSaver : public IniInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IniSaver() = default;
|
virtual ~IniSaver() = default;
|
||||||
explicit IniSaver();
|
explicit IniSaver();
|
||||||
explicit IniSaver(wxConfigBase &config);
|
explicit IniSaver(wxConfigBase& config);
|
||||||
explicit IniSaver(wxConfigBase *config);
|
explicit IniSaver(wxConfigBase* config);
|
||||||
|
|
||||||
bool IsLoading() const { return false; }
|
bool IsLoading() const { return false; }
|
||||||
|
|
||||||
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString());
|
void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString());
|
||||||
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||||
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||||
void Entry(const wxString &var, int &value, const int defvalue = 0);
|
void Entry(const wxString& var, int& value, const int defvalue = 0);
|
||||||
void Entry(const wxString &var, uint &value, const uint defvalue = 0);
|
void Entry(const wxString& var, uint& value, const uint defvalue = 0);
|
||||||
void Entry(const wxString &var, bool &value, const bool defvalue = false);
|
void Entry(const wxString& var, bool& value, const bool defvalue = false);
|
||||||
|
|
||||||
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false);
|
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
|
||||||
int EntryBitfield(const wxString &var, int value, const int defvalue = 0);
|
int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
|
||||||
|
|
||||||
void Entry(const wxString &var, double &value, const double defvalue = 0.0) override;
|
void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
|
||||||
|
|
||||||
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition);
|
void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
|
||||||
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize);
|
void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
|
||||||
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
|
void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue);
|
void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
@ -33,195 +33,198 @@ extern void SignalExit(int sig);
|
||||||
static const uptr m_pagemask = getpagesize() - 1;
|
static const uptr m_pagemask = getpagesize() - 1;
|
||||||
|
|
||||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||||
static void SysPageFaultSignalFilter(int signal, siginfo_t *siginfo, void *)
|
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void*)
|
||||||
{
|
{
|
||||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||||
// process, but the handler is executed by the thread that caused the exception.
|
// process, but the handler is executed by the thread that caused the exception.
|
||||||
|
|
||||||
|
|
||||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||||
// from the context of the current thread and stackframe. So long as the thread is not
|
// from the context of the current thread and stackframe. So long as the thread is not
|
||||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||||
// be safe even on the main thread.
|
// be safe even on the main thread.
|
||||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||||
// signals)
|
// signals)
|
||||||
|
|
||||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||||
// assertions, file logs, or just about anything else useful.
|
// assertions, file logs, or just about anything else useful.
|
||||||
|
|
||||||
|
|
||||||
// Note: This signal can be accessed by the EE or MTVU thread
|
// Note: This signal can be accessed by the EE or MTVU thread
|
||||||
// Source_PageFault is a global variable with its own state information
|
// Source_PageFault is a global variable with its own state information
|
||||||
// so for now we lock this exception code unless someone can fix this better...
|
// so for now we lock this exception code unless someone can fix this better...
|
||||||
Threading::ScopedLock lock(PageFault_Mutex);
|
Threading::ScopedLock lock(PageFault_Mutex);
|
||||||
|
|
||||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
|
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
|
||||||
|
|
||||||
// resumes execution right where we left off (re-executes instruction that
|
// resumes execution right where we left off (re-executes instruction that
|
||||||
// caused the SIGSEGV).
|
// caused the SIGSEGV).
|
||||||
if (Source_PageFault->WasHandled())
|
if (Source_PageFault->WasHandled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!wxThread::IsMain()) {
|
if (!wxThread::IsMain())
|
||||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
{
|
||||||
}
|
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||||
|
}
|
||||||
|
|
||||||
// Bad mojo! Completely invalid address.
|
// Bad mojo! Completely invalid address.
|
||||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||||
|
|
||||||
pxTrap();
|
pxTrap();
|
||||||
if (!IsDebugBuild)
|
if (!IsDebugBuild)
|
||||||
raise(SIGKILL);
|
raise(SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _platform_InstallSignalHandler()
|
void _platform_InstallSignalHandler()
|
||||||
{
|
{
|
||||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// MacOS uses SIGBUS for memory permission violations
|
// MacOS uses SIGBUS for memory permission violations
|
||||||
sigaction(SIGBUS, &sa, NULL);
|
sigaction(SIGBUS, &sa, NULL);
|
||||||
#else
|
#else
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static __ri void PageSizeAssertionTest(size_t size)
|
static __ri void PageSizeAssertionTest(size_t size)
|
||||||
{
|
{
|
||||||
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
|
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
|
||||||
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
|
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
|
||||||
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
|
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
|
||||||
getpagesize(), getpagesize(), __pagesize, __pagesize));
|
getpagesize(), getpagesize(), __pagesize, __pagesize));
|
||||||
|
|
||||||
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
|
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
|
||||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||||
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
|
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
|
||||||
__pagesize, __pagesize, size, size));
|
__pagesize, __pagesize, size, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns FALSE if the mprotect call fails with an ENOMEM.
|
// returns FALSE if the mprotect call fails with an ENOMEM.
|
||||||
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
|
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
|
||||||
// or memory states).
|
// or memory states).
|
||||||
static bool _memprotect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
static bool _memprotect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
PageSizeAssertionTest(size);
|
PageSizeAssertionTest(size);
|
||||||
|
|
||||||
uint lnxmode = 0;
|
uint lnxmode = 0;
|
||||||
|
|
||||||
if (mode.CanWrite())
|
if (mode.CanWrite())
|
||||||
lnxmode |= PROT_WRITE;
|
lnxmode |= PROT_WRITE;
|
||||||
if (mode.CanRead())
|
if (mode.CanRead())
|
||||||
lnxmode |= PROT_READ;
|
lnxmode |= PROT_READ;
|
||||||
if (mode.CanExecute())
|
if (mode.CanExecute())
|
||||||
lnxmode |= PROT_EXEC | PROT_READ;
|
lnxmode |= PROT_EXEC | PROT_READ;
|
||||||
|
|
||||||
const int result = mprotect(baseaddr, size, lnxmode);
|
const int result = mprotect(baseaddr, size, lnxmode);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (errno) {
|
switch (errno)
|
||||||
case EINVAL:
|
{
|
||||||
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
case EINVAL:
|
||||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
break;
|
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||||
|
break;
|
||||||
|
|
||||||
case EACCES:
|
case EACCES:
|
||||||
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
|
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ENOMEM:
|
case ENOMEM:
|
||||||
// caller handles assertion or exception, or whatever.
|
// caller handles assertion or exception, or whatever.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *HostSys::MmapReservePtr(void *base, size_t size)
|
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||||
{
|
{
|
||||||
PageSizeAssertionTest(size);
|
PageSizeAssertionTest(size);
|
||||||
|
|
||||||
// On linux a reserve-without-commit is performed by using mmap on a read-only
|
// On linux a reserve-without-commit is performed by using mmap on a read-only
|
||||||
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
|
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
|
||||||
// is completely inaccessible, the OS will simply reserve it and will not put it
|
// is completely inaccessible, the OS will simply reserve it and will not put it
|
||||||
// against the commit table.
|
// against the commit table.
|
||||||
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode)
|
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
// In linux, reserved memory is automatically committed when its permissions are
|
// In linux, reserved memory is automatically committed when its permissions are
|
||||||
// changed to something other than PROT_NONE. If the user is committing memory
|
// changed to something other than PROT_NONE. If the user is committing memory
|
||||||
// as PROT_NONE, then just ignore this call (memory will be committed automatically
|
// as PROT_NONE, then just ignore this call (memory will be committed automatically
|
||||||
// later when the user changes permissions to something useful via calls to MemProtect).
|
// later when the user changes permissions to something useful via calls to MemProtect).
|
||||||
|
|
||||||
if (mode.IsNone())
|
if (mode.IsNone())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_memprotect(base, size, mode))
|
if (_memprotect(base, size, mode))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!pxDoOutOfMemory)
|
if (!pxDoOutOfMemory)
|
||||||
return false;
|
return false;
|
||||||
pxDoOutOfMemory(size);
|
pxDoOutOfMemory(size);
|
||||||
return _memprotect(base, size, mode);
|
return _memprotect(base, size, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MmapResetPtr(void *base, size_t size)
|
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||||
{
|
{
|
||||||
PageSizeAssertionTest(size);
|
PageSizeAssertionTest(size);
|
||||||
|
|
||||||
void *result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
void* result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||||
|
|
||||||
pxAssertRel((uptr)result == (uptr)base, pxsFmt(
|
pxAssertRel((uptr)result == (uptr)base, pxsFmt(
|
||||||
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
|
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
|
||||||
base, (uptr)base + size));
|
base, (uptr)base + size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *HostSys::MmapReserve(uptr base, size_t size)
|
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
return MmapReservePtr((void *)base, size);
|
return MmapReservePtr((void*)base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode)
|
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
return MmapCommitPtr((void *)base, size, mode);
|
return MmapCommitPtr((void*)base, size, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MmapReset(uptr base, size_t size)
|
void HostSys::MmapReset(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
MmapResetPtr((void *)base, size);
|
MmapResetPtr((void*)base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *HostSys::Mmap(uptr base, size_t size)
|
void* HostSys::Mmap(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
PageSizeAssertionTest(size);
|
PageSizeAssertionTest(size);
|
||||||
|
|
||||||
// MAP_ANONYMOUS - means we have no associated file handle (or device).
|
// MAP_ANONYMOUS - means we have no associated file handle (or device).
|
||||||
|
|
||||||
return mmap((void *)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::Munmap(uptr base, size_t size)
|
void HostSys::Munmap(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
if (!base)
|
if (!base)
|
||||||
return;
|
return;
|
||||||
munmap((void *)base, size);
|
munmap((void*)base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
if (!_memprotect(baseaddr, size, mode)) {
|
if (!_memprotect(baseaddr, size, mode))
|
||||||
throw Exception::OutOfMemory(L"MemProtect")
|
{
|
||||||
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
throw Exception::OutOfMemory(L"MemProtect")
|
||||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
}
|
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,21 +39,21 @@
|
||||||
|
|
||||||
__forceinline void Threading::Sleep(int ms)
|
__forceinline void Threading::Sleep(int ms)
|
||||||
{
|
{
|
||||||
usleep(1000 * ms);
|
usleep(1000 * ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
||||||
// improve performance and reduce cpu power consumption.
|
// improve performance and reduce cpu power consumption.
|
||||||
__forceinline void Threading::SpinWait()
|
__forceinline void Threading::SpinWait()
|
||||||
{
|
{
|
||||||
// If this doesn't compile you can just comment it out (it only serves as a
|
// If this doesn't compile you can just comment it out (it only serves as a
|
||||||
// performance hint and isn't required).
|
// performance hint and isn't required).
|
||||||
__asm__("pause");
|
__asm__("pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void Threading::EnableHiresScheduler()
|
__forceinline void Threading::EnableHiresScheduler()
|
||||||
{
|
{
|
||||||
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
|
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void Threading::DisableHiresScheduler()
|
__forceinline void Threading::DisableHiresScheduler()
|
||||||
|
@ -63,69 +63,72 @@ __forceinline void Threading::DisableHiresScheduler()
|
||||||
// Unit of time of GetThreadCpuTime/GetCpuTime
|
// Unit of time of GetThreadCpuTime/GetCpuTime
|
||||||
u64 Threading::GetThreadTicksPerSecond()
|
u64 Threading::GetThreadTicksPerSecond()
|
||||||
{
|
{
|
||||||
return 1000000;
|
return 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get either either the current cpu usage
|
// Helper function to get either either the current cpu usage
|
||||||
// in called thread or in id thread
|
// in called thread or in id thread
|
||||||
static u64 get_thread_time(uptr id = 0)
|
static u64 get_thread_time(uptr id = 0)
|
||||||
{
|
{
|
||||||
clockid_t cid;
|
clockid_t cid;
|
||||||
if (id) {
|
if (id)
|
||||||
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
{
|
||||||
if (err)
|
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
||||||
return 0;
|
if (err)
|
||||||
} else {
|
return 0;
|
||||||
cid = CLOCK_THREAD_CPUTIME_ID;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
cid = CLOCK_THREAD_CPUTIME_ID;
|
||||||
|
}
|
||||||
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int err = clock_gettime(cid, &ts);
|
int err = clock_gettime(cid, &ts);
|
||||||
if (err)
|
if (err)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3;
|
return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current timestamp (not relative to a real world clock)
|
// Returns the current timestamp (not relative to a real world clock)
|
||||||
u64 Threading::GetThreadCpuTime()
|
u64 Threading::GetThreadCpuTime()
|
||||||
{
|
{
|
||||||
return get_thread_time();
|
return get_thread_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Threading::pxThread::GetCpuTime() const
|
u64 Threading::pxThread::GetCpuTime() const
|
||||||
{
|
{
|
||||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||||
// which typically would be an OS-provided scalar or some sort).
|
// which typically would be an OS-provided scalar or some sort).
|
||||||
|
|
||||||
if (!m_native_id)
|
if (!m_native_id)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return get_thread_time(m_native_id);
|
return get_thread_time(m_native_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||||
{
|
{
|
||||||
// Obtain linux-specific thread IDs or Handles here, which can be used to query
|
// Obtain linux-specific thread IDs or Handles here, which can be used to query
|
||||||
// kernel scheduler performance information.
|
// kernel scheduler performance information.
|
||||||
m_native_id = (uptr)pthread_self();
|
m_native_id = (uptr)pthread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||||
{
|
{
|
||||||
// Cleanup handles here, which were opened above.
|
// Cleanup handles here, which were opened above.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::SetNameOfCurrentThread(const char *name)
|
void Threading::SetNameOfCurrentThread(const char* name)
|
||||||
{
|
{
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
// Extract of manpage: "The name can be up to 16 bytes long, and should be
|
// Extract of manpage: "The name can be up to 16 bytes long, and should be
|
||||||
// null-terminated if it contains fewer bytes."
|
// null-terminated if it contains fewer bytes."
|
||||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||||
#elif defined(__unix__)
|
#elif defined(__unix__)
|
||||||
pthread_set_name_np(pthread_self(), name);
|
pthread_set_name_np(pthread_self(), name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,20 +22,20 @@
|
||||||
// On GCC >= 4.7, this is equivalent to __builtin_clrsb(n);
|
// On GCC >= 4.7, this is equivalent to __builtin_clrsb(n);
|
||||||
inline u32 count_leading_sign_bits(s32 n)
|
inline u32 count_leading_sign_bits(s32 n)
|
||||||
{
|
{
|
||||||
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
|
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
n = ~n;
|
n = ~n;
|
||||||
|
|
||||||
// If BSR is used directly, it would have an undefined value for 0.
|
// If BSR is used directly, it would have an undefined value for 0.
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return 32;
|
return 32;
|
||||||
|
|
||||||
// Perform our count leading zero.
|
// Perform our count leading zero.
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
_BitScanReverse(&ret, n);
|
_BitScanReverse(&ret, n);
|
||||||
return 31 - (u32)ret;
|
return 31 - (u32)ret;
|
||||||
#else
|
#else
|
||||||
return __builtin_clz(n);
|
return __builtin_clz(n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
|
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
|
||||||
// other implementations. So for this combination only, prefer memcmp_mmx
|
// other implementations. So for this combination only, prefer memcmp_mmx
|
||||||
#if defined(_MSC_VER) && !defined(_M_X86_64)
|
#if defined(_MSC_VER) && !defined(_M_X86_64)
|
||||||
extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize);
|
extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize);
|
||||||
#else
|
#else
|
||||||
#define memcmp_mmx memcmp
|
#define memcmp_mmx memcmp
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,14 +31,14 @@ extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize);
|
||||||
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
||||||
// for you!
|
// for you!
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static __fi void memzero(T &object)
|
static __fi void memzero(T& object)
|
||||||
{
|
{
|
||||||
memset(&object, 0, sizeof(T));
|
memset(&object, 0, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method clears an object with the given 8 bit value.
|
// This method clears an object with the given 8 bit value.
|
||||||
template <u8 data, typename T>
|
template <u8 data, typename T>
|
||||||
static __fi void memset8(T &object)
|
static __fi void memset8(T& object)
|
||||||
{
|
{
|
||||||
memset(&object, data, sizeof(T));
|
memset(&object, data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,74 +18,78 @@
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
|
||||||
template <u8 data>
|
template <u8 data>
|
||||||
__noinline void memset_sse_a(void *dest, const size_t size)
|
__noinline void memset_sse_a(void* dest, const size_t size)
|
||||||
{
|
{
|
||||||
const uint MZFqwc = size / 16;
|
const uint MZFqwc = size / 16;
|
||||||
|
|
||||||
pxAssert((size & 0xf) == 0);
|
pxAssert((size & 0xf) == 0);
|
||||||
|
|
||||||
__m128 srcreg;
|
__m128 srcreg;
|
||||||
|
|
||||||
if (data != 0) {
|
if (data != 0)
|
||||||
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
{
|
||||||
srcreg = _mm_loadh_pi(_mm_load_ps((float *)loadval), (__m64 *)loadval);
|
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
||||||
} else
|
srcreg = _mm_loadh_pi(_mm_load_ps((float*)loadval), (__m64*)loadval);
|
||||||
srcreg = _mm_setzero_ps();
|
}
|
||||||
|
else
|
||||||
|
srcreg = _mm_setzero_ps();
|
||||||
|
|
||||||
float(*destxmm)[4] = (float(*)[4])dest;
|
float(*destxmm)[4] = (float(*)[4])dest;
|
||||||
|
|
||||||
switch (MZFqwc & 0x07) {
|
switch (MZFqwc & 0x07)
|
||||||
case 0x07:
|
{
|
||||||
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
case 0x07:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
||||||
case 0x06:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
|
case 0x06:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
|
||||||
case 0x05:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
|
case 0x05:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
|
||||||
case 0x04:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
|
case 0x04:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
|
||||||
case 0x03:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
|
case 0x03:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
|
||||||
case 0x02:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
|
case 0x02:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
|
||||||
case 0x01:
|
// Fall through
|
||||||
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
|
case 0x01:
|
||||||
// Fall through
|
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
|
||||||
}
|
// Fall through
|
||||||
|
}
|
||||||
|
|
||||||
destxmm += (MZFqwc & 0x07);
|
destxmm += (MZFqwc & 0x07);
|
||||||
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8) {
|
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8)
|
||||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
{
|
||||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||||
}
|
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static __fi void memzero_sse_a(void *dest, const size_t size)
|
static __fi void memzero_sse_a(void* dest, const size_t size)
|
||||||
{
|
{
|
||||||
memset_sse_a<0>(dest, size);
|
memset_sse_a<0>(dest, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <u8 data, typename T>
|
template <u8 data, typename T>
|
||||||
__noinline void memset_sse_a(T &dest)
|
__noinline void memset_sse_a(T& dest)
|
||||||
{
|
{
|
||||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||||
memset_sse_a<data>(&dest, sizeof(dest));
|
memset_sse_a<data>(&dest, sizeof(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void memzero_sse_a(T &dest)
|
void memzero_sse_a(T& dest)
|
||||||
{
|
{
|
||||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||||
memset_sse_a<0>(&dest, sizeof(dest));
|
memset_sse_a<0>(&dest, sizeof(dest));
|
||||||
}
|
}
|
||||||
|
|
318
common/Mutex.cpp
318
common/Mutex.cpp
|
@ -20,9 +20,9 @@
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
static std::atomic<int> _attr_refcount(0);
|
static std::atomic<int> _attr_refcount(0);
|
||||||
static pthread_mutexattr_t _attr_recursive;
|
static pthread_mutexattr_t _attr_recursive;
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Mutex Implementations
|
// Mutex Implementations
|
||||||
|
@ -52,90 +52,94 @@ static pthread_mutexattr_t _attr_recursive;
|
||||||
// This is an implementation that emulates pthread_mutex_timedlock() via
|
// This is an implementation that emulates pthread_mutex_timedlock() via
|
||||||
// pthread_mutex_trylock().
|
// pthread_mutex_trylock().
|
||||||
static int xpthread_mutex_timedlock(
|
static int xpthread_mutex_timedlock(
|
||||||
pthread_mutex_t *mutex,
|
pthread_mutex_t* mutex,
|
||||||
const struct timespec *abs_timeout)
|
const struct timespec* abs_timeout)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
while ((err = pthread_mutex_trylock(mutex)) == EBUSY) {
|
while ((err = pthread_mutex_trylock(mutex)) == EBUSY)
|
||||||
// check if the timeout has expired, gettimeofday() is implemented
|
{
|
||||||
// efficiently (in userspace) on OSX
|
// check if the timeout has expired, gettimeofday() is implemented
|
||||||
struct timeval now;
|
// efficiently (in userspace) on OSX
|
||||||
gettimeofday(&now, NULL);
|
struct timeval now;
|
||||||
if (now.tv_sec > abs_timeout->tv_sec
|
gettimeofday(&now, NULL);
|
||||||
|| (now.tv_sec == abs_timeout->tv_sec
|
if (now.tv_sec > abs_timeout->tv_sec || (now.tv_sec == abs_timeout->tv_sec && (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec))
|
||||||
&& (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec)) {
|
{
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// acquiring lock failed, sleep some
|
// acquiring lock failed, sleep some
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
ts.tv_sec = 0;
|
ts.tv_sec = 0;
|
||||||
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
||||||
while (nanosleep(&ts, &ts) == -1);
|
while (nanosleep(&ts, &ts) == -1)
|
||||||
}
|
;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Threading::Mutex::Mutex()
|
Threading::Mutex::Mutex()
|
||||||
{
|
{
|
||||||
pthread_mutex_init(&m_mutex, NULL);
|
pthread_mutex_init(&m_mutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxTimeSpan def_detach_timeout(0, 0, 6, 0);
|
static wxTimeSpan def_detach_timeout(0, 0, 6, 0);
|
||||||
|
|
||||||
void Threading::Mutex::Detach()
|
void Threading::Mutex::Detach()
|
||||||
{
|
{
|
||||||
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsRecursive()) {
|
if (IsRecursive())
|
||||||
// Sanity check: Recursive locks could be held by our own thread, which would
|
{
|
||||||
// be considered an assertion failure, but can also be handled gracefully.
|
// Sanity check: Recursive locks could be held by our own thread, which would
|
||||||
// (note: if the mutex is locked recursively more than twice then this assert won't
|
// be considered an assertion failure, but can also be handled gracefully.
|
||||||
// detect it)
|
// (note: if the mutex is locked recursively more than twice then this assert won't
|
||||||
|
// detect it)
|
||||||
|
|
||||||
Release();
|
Release();
|
||||||
Release(); // in case of double recursion.
|
Release(); // in case of double recursion.
|
||||||
int result = pthread_mutex_destroy(&m_mutex);
|
int result = pthread_mutex_destroy(&m_mutex);
|
||||||
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
|
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Wait(def_detach_timeout))
|
if (Wait(def_detach_timeout))
|
||||||
pthread_mutex_destroy(&m_mutex);
|
pthread_mutex_destroy(&m_mutex);
|
||||||
else
|
else
|
||||||
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
|
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::Mutex::~Mutex()
|
Threading::Mutex::~Mutex()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
Mutex::Detach();
|
{
|
||||||
}
|
Mutex::Detach();
|
||||||
DESTRUCTOR_CATCHALL;
|
}
|
||||||
|
DESTRUCTOR_CATCHALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::MutexRecursive::MutexRecursive()
|
Threading::MutexRecursive::MutexRecursive()
|
||||||
: Mutex(false)
|
: Mutex(false)
|
||||||
{
|
{
|
||||||
if (++_attr_refcount == 1) {
|
if (++_attr_refcount == 1)
|
||||||
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
{
|
||||||
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
||||||
|
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
||||||
|
|
||||||
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_mutex_init(&m_mutex, &_attr_recursive))
|
if (pthread_mutex_init(&m_mutex, &_attr_recursive))
|
||||||
Console.Error("(Thread Log) Failed to initialize mutex.");
|
Console.Error("(Thread Log) Failed to initialize mutex.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::MutexRecursive::~MutexRecursive()
|
Threading::MutexRecursive::~MutexRecursive()
|
||||||
{
|
{
|
||||||
if (--_attr_refcount == 0)
|
if (--_attr_refcount == 0)
|
||||||
pthread_mutexattr_destroy(&_attr_recursive);
|
pthread_mutexattr_destroy(&_attr_recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a bit of a hackish function, which is technically unsafe, but can be useful for allowing
|
// This is a bit of a hackish function, which is technically unsafe, but can be useful for allowing
|
||||||
|
@ -144,8 +148,8 @@ Threading::MutexRecursive::~MutexRecursive()
|
||||||
// the deeper meanings of the universe for eternity.
|
// the deeper meanings of the universe for eternity.
|
||||||
void Threading::Mutex::Recreate()
|
void Threading::Mutex::Recreate()
|
||||||
{
|
{
|
||||||
Detach();
|
Detach();
|
||||||
pthread_mutex_init(&m_mutex, NULL);
|
pthread_mutex_init(&m_mutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns:
|
// Returns:
|
||||||
|
@ -153,11 +157,12 @@ void Threading::Mutex::Recreate()
|
||||||
// unlocked.
|
// unlocked.
|
||||||
bool Threading::Mutex::RecreateIfLocked()
|
bool Threading::Mutex::RecreateIfLocked()
|
||||||
{
|
{
|
||||||
if (!Wait(def_detach_timeout)) {
|
if (!Wait(def_detach_timeout))
|
||||||
Recreate();
|
{
|
||||||
return true;
|
Recreate();
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,25 +172,25 @@ bool Threading::Mutex::RecreateIfLocked()
|
||||||
// other than the main thread.
|
// other than the main thread.
|
||||||
void Threading::Mutex::AcquireWithoutYield()
|
void Threading::Mutex::AcquireWithoutYield()
|
||||||
{
|
{
|
||||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
|
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
|
||||||
pthread_mutex_lock(&m_mutex);
|
pthread_mutex_lock(&m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan &timeout)
|
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||||
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
|
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Mutex::Release()
|
void Threading::Mutex::Release()
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&m_mutex);
|
pthread_mutex_unlock(&m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Mutex::TryAcquire()
|
bool Threading::Mutex::TryAcquire()
|
||||||
{
|
{
|
||||||
return EBUSY != pthread_mutex_trylock(&m_mutex);
|
return EBUSY != pthread_mutex_trylock(&m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events
|
// This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events
|
||||||
|
@ -194,45 +199,56 @@ bool Threading::Mutex::TryAcquire()
|
||||||
void Threading::Mutex::Acquire()
|
void Threading::Mutex::Acquire()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
pthread_mutex_lock(&m_mutex);
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Mutex::Acquire")) {
|
pthread_mutex_lock(&m_mutex);
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
pthread_mutex_lock(&m_mutex);
|
else if (_WaitGui_RecursionGuard(L"Mutex::Acquire"))
|
||||||
} else {
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
while (!AcquireWithoutYield(def_yieldgui_interval))
|
pthread_mutex_lock(&m_mutex);
|
||||||
YieldToMain();
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
|
while (!AcquireWithoutYield(def_yieldgui_interval))
|
||||||
|
YieldToMain();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
pthread_mutex_lock(&m_mutex);
|
pthread_mutex_lock(&m_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
|
bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
return AcquireWithoutYield(timeout);
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire")) {
|
return AcquireWithoutYield(timeout);
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
return AcquireWithoutYield(timeout);
|
else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire"))
|
||||||
} else {
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
wxTimeSpan countdown((timeout));
|
return AcquireWithoutYield(timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
if (AcquireWithoutYield(def_yieldgui_interval))
|
{
|
||||||
break;
|
if (AcquireWithoutYield(def_yieldgui_interval))
|
||||||
YieldToMain();
|
break;
|
||||||
countdown -= def_yieldgui_interval;
|
YieldToMain();
|
||||||
} while (countdown.GetMilliseconds() > 0);
|
countdown -= def_yieldgui_interval;
|
||||||
|
} while (countdown.GetMilliseconds() > 0);
|
||||||
|
|
||||||
return countdown.GetMilliseconds() > 0;
|
return countdown.GetMilliseconds() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return AcquireWithoutYield();
|
return AcquireWithoutYield();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,14 +261,14 @@ bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
|
||||||
//
|
//
|
||||||
void Threading::Mutex::Wait()
|
void Threading::Mutex::Wait()
|
||||||
{
|
{
|
||||||
Acquire();
|
Acquire();
|
||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Mutex::WaitWithoutYield()
|
void Threading::Mutex::WaitWithoutYield()
|
||||||
{
|
{
|
||||||
AcquireWithoutYield();
|
AcquireWithoutYield();
|
||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked.
|
// Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked.
|
||||||
|
@ -262,22 +278,24 @@ void Threading::Mutex::WaitWithoutYield()
|
||||||
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out
|
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out
|
||||||
// and the mutex is still locked by another thread.
|
// and the mutex is still locked by another thread.
|
||||||
//
|
//
|
||||||
bool Threading::Mutex::Wait(const wxTimeSpan &timeout)
|
bool Threading::Mutex::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
if (Acquire(timeout)) {
|
if (Acquire(timeout))
|
||||||
Release();
|
{
|
||||||
return true;
|
Release();
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
|
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
if (AcquireWithoutYield(timeout)) {
|
if (AcquireWithoutYield(timeout))
|
||||||
Release();
|
{
|
||||||
return true;
|
Release();
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -286,72 +304,72 @@ bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
|
|
||||||
Threading::ScopedLock::~ScopedLock()
|
Threading::ScopedLock::~ScopedLock()
|
||||||
{
|
{
|
||||||
if (m_IsLocked && m_lock)
|
if (m_IsLocked && m_lock)
|
||||||
m_lock->Release();
|
m_lock->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::ScopedLock::ScopedLock(const Mutex *locker)
|
Threading::ScopedLock::ScopedLock(const Mutex* locker)
|
||||||
{
|
{
|
||||||
m_IsLocked = false;
|
m_IsLocked = false;
|
||||||
AssignAndLock(locker);
|
AssignAndLock(locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::ScopedLock::ScopedLock(const Mutex &locker)
|
Threading::ScopedLock::ScopedLock(const Mutex& locker)
|
||||||
{
|
{
|
||||||
m_IsLocked = false;
|
m_IsLocked = false;
|
||||||
AssignAndLock(locker);
|
AssignAndLock(locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::ScopedLock::AssignAndLock(const Mutex &locker)
|
void Threading::ScopedLock::AssignAndLock(const Mutex& locker)
|
||||||
{
|
{
|
||||||
AssignAndLock(&locker);
|
AssignAndLock(&locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::ScopedLock::AssignAndLock(const Mutex *locker)
|
void Threading::ScopedLock::AssignAndLock(const Mutex* locker)
|
||||||
{
|
{
|
||||||
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
|
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
|
||||||
|
|
||||||
m_lock = const_cast<Mutex *>(locker);
|
m_lock = const_cast<Mutex*>(locker);
|
||||||
if (!m_lock)
|
if (!m_lock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
m_lock->Acquire();
|
m_lock->Acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::ScopedLock::Assign(const Mutex &locker)
|
void Threading::ScopedLock::Assign(const Mutex& locker)
|
||||||
{
|
{
|
||||||
m_lock = const_cast<Mutex *>(&locker);
|
m_lock = const_cast<Mutex*>(&locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::ScopedLock::Assign(const Mutex *locker)
|
void Threading::ScopedLock::Assign(const Mutex* locker)
|
||||||
{
|
{
|
||||||
m_lock = const_cast<Mutex *>(locker);
|
m_lock = const_cast<Mutex*>(locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provides manual unlocking of a scoped lock prior to object destruction.
|
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||||
void Threading::ScopedLock::Release()
|
void Threading::ScopedLock::Release()
|
||||||
{
|
{
|
||||||
if (!m_IsLocked)
|
if (!m_IsLocked)
|
||||||
return;
|
return;
|
||||||
m_IsLocked = false;
|
m_IsLocked = false;
|
||||||
if (m_lock)
|
if (m_lock)
|
||||||
m_lock->Release();
|
m_lock->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||||
void Threading::ScopedLock::Acquire()
|
void Threading::ScopedLock::Acquire()
|
||||||
{
|
{
|
||||||
if (m_IsLocked || !m_lock)
|
if (m_IsLocked || !m_lock)
|
||||||
return;
|
return;
|
||||||
m_lock->Acquire();
|
m_lock->Acquire();
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::ScopedLock::ScopedLock(const Mutex &locker, bool isTryLock)
|
Threading::ScopedLock::ScopedLock(const Mutex& locker, bool isTryLock)
|
||||||
{
|
{
|
||||||
m_lock = const_cast<Mutex *>(&locker);
|
m_lock = const_cast<Mutex*>(&locker);
|
||||||
if (!m_lock)
|
if (!m_lock)
|
||||||
return;
|
return;
|
||||||
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
|
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@
|
||||||
|
|
||||||
struct PageFaultInfo
|
struct PageFaultInfo
|
||||||
{
|
{
|
||||||
uptr addr;
|
uptr addr;
|
||||||
|
|
||||||
PageFaultInfo(uptr address)
|
PageFaultInfo(uptr address)
|
||||||
{
|
{
|
||||||
addr = address;
|
addr = address;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -44,22 +44,22 @@ struct PageFaultInfo
|
||||||
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef PageFaultInfo EvtParams;
|
typedef PageFaultInfo EvtParams;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~IEventListener_PageFault() = default;
|
virtual ~IEventListener_PageFault() = default;
|
||||||
|
|
||||||
virtual void DispatchEvent(const PageFaultInfo &evtinfo, bool &handled)
|
virtual void DispatchEvent(const PageFaultInfo& evtinfo, bool& handled)
|
||||||
{
|
{
|
||||||
OnPageFaultEvent(evtinfo, handled);
|
OnPageFaultEvent(evtinfo, handled);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void DispatchEvent(const PageFaultInfo &evtinfo)
|
virtual void DispatchEvent(const PageFaultInfo& evtinfo)
|
||||||
{
|
{
|
||||||
pxFailRel("Don't call me, damnit. Use DispatchException instead.");
|
pxFailRel("Don't call me, damnit. Use DispatchException instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnPageFaultEvent(const PageFaultInfo &evtinfo, bool &handled) {}
|
virtual void OnPageFaultEvent(const PageFaultInfo& evtinfo, bool& handled) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -68,34 +68,34 @@ public:
|
||||||
class EventListener_PageFault : public IEventListener_PageFault
|
class EventListener_PageFault : public IEventListener_PageFault
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EventListener_PageFault();
|
EventListener_PageFault();
|
||||||
virtual ~EventListener_PageFault();
|
virtual ~EventListener_PageFault();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TypeToDispatchTo>
|
template <typename TypeToDispatchTo>
|
||||||
class EventListenerHelper_PageFault : public EventListener_PageFault
|
class EventListenerHelper_PageFault : public EventListener_PageFault
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TypeToDispatchTo *Owner;
|
TypeToDispatchTo* Owner;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EventListenerHelper_PageFault(TypeToDispatchTo &dispatchTo)
|
EventListenerHelper_PageFault(TypeToDispatchTo& dispatchTo)
|
||||||
{
|
{
|
||||||
Owner = &dispatchTo;
|
Owner = &dispatchTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListenerHelper_PageFault(TypeToDispatchTo *dispatchTo)
|
EventListenerHelper_PageFault(TypeToDispatchTo* dispatchTo)
|
||||||
{
|
{
|
||||||
Owner = dispatchTo;
|
Owner = dispatchTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~EventListenerHelper_PageFault() = default;
|
virtual ~EventListenerHelper_PageFault() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnPageFaultEvent(const PageFaultInfo &info, bool &handled)
|
virtual void OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||||
{
|
{
|
||||||
Owner->OnPageFaultEvent(info, handled);
|
Owner->OnPageFaultEvent(info, handled);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -104,23 +104,23 @@ protected:
|
||||||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef EventSource<IEventListener_PageFault> _parent;
|
typedef EventSource<IEventListener_PageFault> _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_handled;
|
bool m_handled;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrcType_PageFault()
|
SrcType_PageFault()
|
||||||
: m_handled(false)
|
: m_handled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~SrcType_PageFault() = default;
|
virtual ~SrcType_PageFault() = default;
|
||||||
|
|
||||||
bool WasHandled() const { return m_handled; }
|
bool WasHandled() const { return m_handled; }
|
||||||
virtual void Dispatch(const PageFaultInfo ¶ms);
|
virtual void Dispatch(const PageFaultInfo& params);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt);
|
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,40 +130,41 @@ protected:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class VirtualMemoryManager
|
class VirtualMemoryManager
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(VirtualMemoryManager);
|
DeclareNoncopyableObject(VirtualMemoryManager);
|
||||||
|
|
||||||
wxString m_name;
|
wxString m_name;
|
||||||
|
|
||||||
uptr m_baseptr;
|
uptr m_baseptr;
|
||||||
|
|
||||||
// An array to track page usage (to trigger asserts if things try to overlap)
|
// An array to track page usage (to trigger asserts if things try to overlap)
|
||||||
std::atomic<bool> *m_pageuse;
|
std::atomic<bool>* m_pageuse;
|
||||||
|
|
||||||
// reserved memory (in pages)
|
// reserved memory (in pages)
|
||||||
u32 m_pages_reserved;
|
u32 m_pages_reserved;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
|
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
|
||||||
// calls to IsOk() will return false and Alloc() will always return null pointers
|
// calls to IsOk() will return false and Alloc() will always return null pointers
|
||||||
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
|
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
|
||||||
VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
|
VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
|
||||||
~VirtualMemoryManager();
|
~VirtualMemoryManager();
|
||||||
|
|
||||||
void *GetBase() const { return (void *)m_baseptr; }
|
void* GetBase() const { return (void*)m_baseptr; }
|
||||||
|
|
||||||
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
|
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
|
||||||
// offsetLocation must be page-aligned
|
// offsetLocation must be page-aligned
|
||||||
void *Alloc(uptr offsetLocation, size_t size) const;
|
void* Alloc(uptr offsetLocation, size_t size) const;
|
||||||
|
|
||||||
void *AllocAtAddress(void *address, size_t size) const {
|
void* AllocAtAddress(void* address, size_t size) const
|
||||||
return Alloc(size, (uptr)address - m_baseptr);
|
{
|
||||||
}
|
return Alloc(size, (uptr)address - m_baseptr);
|
||||||
|
}
|
||||||
|
|
||||||
void Free(void *address, size_t size) const;
|
void Free(void* address, size_t size) const;
|
||||||
|
|
||||||
// Was this VirtualMemoryManager successfully able to get its memory mapping?
|
// Was this VirtualMemoryManager successfully able to get its memory mapping?
|
||||||
// (If not, calls to Alloc will return null pointers)
|
// (If not, calls to Alloc will return null pointers)
|
||||||
bool IsOk() const { return m_baseptr != 0; }
|
bool IsOk() const { return m_baseptr != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
||||||
|
@ -173,13 +174,14 @@ typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class VirtualMemoryBumpAllocator
|
class VirtualMemoryBumpAllocator
|
||||||
{
|
{
|
||||||
const VirtualMemoryManagerPtr m_allocator;
|
const VirtualMemoryManagerPtr m_allocator;
|
||||||
std::atomic<uptr> m_baseptr{0};
|
std::atomic<uptr> m_baseptr{0};
|
||||||
const uptr m_endptr = 0;
|
const uptr m_endptr = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
||||||
void *Alloc(size_t size);
|
void* Alloc(size_t size);
|
||||||
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
|
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -187,108 +189,108 @@ public:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class VirtualMemoryReserve
|
class VirtualMemoryReserve
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(VirtualMemoryReserve);
|
DeclareNoncopyableObject(VirtualMemoryReserve);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_name;
|
wxString m_name;
|
||||||
|
|
||||||
// Where the memory came from (so we can return it)
|
// Where the memory came from (so we can return it)
|
||||||
VirtualMemoryManagerPtr m_allocator;
|
VirtualMemoryManagerPtr m_allocator;
|
||||||
|
|
||||||
// Default size of the reserve, in bytes. Can be specified when the object is constructed.
|
// Default size of the reserve, in bytes. Can be specified when the object is constructed.
|
||||||
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
||||||
// in the Reserve parameters.
|
// in the Reserve parameters.
|
||||||
size_t m_defsize;
|
size_t m_defsize;
|
||||||
|
|
||||||
void *m_baseptr;
|
void* m_baseptr;
|
||||||
|
|
||||||
// reserved memory (in pages).
|
// reserved memory (in pages).
|
||||||
uptr m_pages_reserved;
|
uptr m_pages_reserved;
|
||||||
|
|
||||||
// Records the number of pages committed to memory.
|
// Records the number of pages committed to memory.
|
||||||
// (metric for analysis of buffer usage)
|
// (metric for analysis of buffer usage)
|
||||||
uptr m_pages_commited;
|
uptr m_pages_commited;
|
||||||
|
|
||||||
// Protection mode to be applied to committed blocks.
|
// Protection mode to be applied to committed blocks.
|
||||||
PageProtectionMode m_prot_mode;
|
PageProtectionMode m_prot_mode;
|
||||||
|
|
||||||
// Controls write access to the entire reserve. When true (the default), the reserve
|
// Controls write access to the entire reserve. When true (the default), the reserve
|
||||||
// operates normally. When set to false, all committed blocks are re-protected with
|
// operates normally. When set to false, all committed blocks are re-protected with
|
||||||
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
|
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
|
||||||
// as well.
|
// as well.
|
||||||
bool m_allow_writes;
|
bool m_allow_writes;
|
||||||
|
|
||||||
// Allows the implementation to decide how much memory it needs to allocate if someone requests the given size
|
// Allows the implementation to decide how much memory it needs to allocate if someone requests the given size
|
||||||
// Should translate requests of size 0 to m_defsize
|
// Should translate requests of size 0 to m_defsize
|
||||||
virtual size_t GetSize(size_t requestedSize);
|
virtual size_t GetSize(size_t requestedSize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VirtualMemoryReserve(const wxString &name, size_t size = 0);
|
VirtualMemoryReserve(const wxString& name, size_t size = 0);
|
||||||
virtual ~VirtualMemoryReserve()
|
virtual ~VirtualMemoryReserve()
|
||||||
{
|
{
|
||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize with the given piece of memory
|
// Initialize with the given piece of memory
|
||||||
// Note: The memory is already allocated, the allocator is for future use to free the region
|
// Note: The memory is already allocated, the allocator is for future use to free the region
|
||||||
// It may be null in which case there is no way to free the memory in a way it will be usable again
|
// It may be null in which case there is no way to free the memory in a way it will be usable again
|
||||||
virtual void *Assign(VirtualMemoryManagerPtr allocator, void *baseptr, size_t size);
|
virtual void* Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size);
|
||||||
|
|
||||||
void *Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
|
void* Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
|
||||||
{
|
{
|
||||||
size = GetSize(size);
|
size = GetSize(size);
|
||||||
void *allocation = allocator->Alloc(baseOffset, size);
|
void* allocation = allocator->Alloc(baseOffset, size);
|
||||||
return Assign(std::move(allocator), allocation, size);
|
return Assign(std::move(allocator), allocation, size);
|
||||||
}
|
}
|
||||||
void *Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
|
void* Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
|
||||||
{
|
{
|
||||||
size = GetSize(size);
|
size = GetSize(size);
|
||||||
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
|
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
virtual void Release();
|
virtual void Release();
|
||||||
virtual bool TryResize(uint newsize);
|
virtual bool TryResize(uint newsize);
|
||||||
virtual bool Commit();
|
virtual bool Commit();
|
||||||
|
|
||||||
virtual void ForbidModification();
|
virtual void ForbidModification();
|
||||||
virtual void AllowModification();
|
virtual void AllowModification();
|
||||||
|
|
||||||
bool IsOk() const { return m_baseptr != NULL; }
|
bool IsOk() const { return m_baseptr != NULL; }
|
||||||
const wxString& GetName() const { return m_name; }
|
const wxString& GetName() const { return m_name; }
|
||||||
|
|
||||||
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
||||||
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
||||||
uint GetCommittedPageCount() const { return m_pages_commited; }
|
uint GetCommittedPageCount() const { return m_pages_commited; }
|
||||||
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
||||||
|
|
||||||
u8 *GetPtr() { return (u8 *)m_baseptr; }
|
u8* GetPtr() { return (u8*)m_baseptr; }
|
||||||
const u8 *GetPtr() const { return (u8 *)m_baseptr; }
|
const u8* GetPtr() const { return (u8*)m_baseptr; }
|
||||||
u8 *GetPtrEnd() { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
|
u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||||
const u8 *GetPtrEnd() const { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
|
const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||||
|
|
||||||
VirtualMemoryReserve &SetPageAccessOnCommit(const PageProtectionMode &mode);
|
VirtualMemoryReserve& SetPageAccessOnCommit(const PageProtectionMode& mode);
|
||||||
|
|
||||||
operator void *() { return m_baseptr; }
|
operator void*() { return m_baseptr; }
|
||||||
operator const void *() const { return m_baseptr; }
|
operator const void*() const { return m_baseptr; }
|
||||||
|
|
||||||
operator u8 *() { return (u8 *)m_baseptr; }
|
operator u8*() { return (u8*)m_baseptr; }
|
||||||
operator const u8 *() const { return (u8 *)m_baseptr; }
|
operator const u8*() const { return (u8*)m_baseptr; }
|
||||||
|
|
||||||
u8 &operator[](uint idx)
|
u8& operator[](uint idx)
|
||||||
{
|
{
|
||||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||||
return *((u8 *)m_baseptr + idx);
|
return *((u8*)m_baseptr + idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 &operator[](uint idx) const
|
const u8& operator[](uint idx) const
|
||||||
{
|
{
|
||||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||||
return *((u8 *)m_baseptr + idx);
|
return *((u8*)m_baseptr + idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void ReprotectCommittedBlocks(const PageProtectionMode &newmode);
|
virtual void ReprotectCommittedBlocks(const PageProtectionMode& newmode);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
|
@ -299,11 +301,11 @@ protected:
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
struct _EXCEPTION_POINTERS;
|
struct _EXCEPTION_POINTERS;
|
||||||
extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS *eps);
|
extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||||
|
|
||||||
#define PCSX2_PAGEFAULT_PROTECT __try
|
#define PCSX2_PAGEFAULT_PROTECT __try
|
||||||
#define PCSX2_PAGEFAULT_EXCEPT \
|
#define PCSX2_PAGEFAULT_EXCEPT \
|
||||||
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error PCSX2 - Unsupported operating system platform.
|
#error PCSX2 - Unsupported operating system platform.
|
||||||
|
@ -313,5 +315,5 @@ extern void pxInstallSignalHandler();
|
||||||
extern void _platform_InstallSignalHandler();
|
extern void _platform_InstallSignalHandler();
|
||||||
|
|
||||||
#include "Threading.h"
|
#include "Threading.h"
|
||||||
extern SrcType_PageFault *Source_PageFault;
|
extern SrcType_PageFault* Source_PageFault;
|
||||||
extern Threading::Mutex PageFault_Mutex;
|
extern Threading::Mutex PageFault_Mutex;
|
||||||
|
|
312
common/Path.h
312
common/Path.h
|
@ -26,180 +26,184 @@
|
||||||
class wxDirName : protected wxFileName
|
class wxDirName : protected wxFileName
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit wxDirName(const wxFileName &src)
|
explicit wxDirName(const wxFileName& src)
|
||||||
{
|
{
|
||||||
Assign(src.GetPath(), wxEmptyString);
|
Assign(src.GetPath(), wxEmptyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDirName()
|
wxDirName()
|
||||||
: wxFileName()
|
: wxFileName()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
wxDirName(const wxDirName &src)
|
wxDirName(const wxDirName& src)
|
||||||
: wxFileName(src)
|
: wxFileName(src)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
explicit wxDirName(const char *src) { Assign(fromUTF8(src)); }
|
explicit wxDirName(const char* src) { Assign(fromUTF8(src)); }
|
||||||
explicit wxDirName(const wxString &src) { Assign(src); }
|
explicit wxDirName(const wxString& src) { Assign(src); }
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void Assign(const wxString &volume, const wxString &path)
|
void Assign(const wxString& volume, const wxString& path)
|
||||||
{
|
{
|
||||||
wxFileName::Assign(volume, path, wxEmptyString);
|
wxFileName::Assign(volume, path, wxEmptyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assign(const wxString &path)
|
void Assign(const wxString& path)
|
||||||
{
|
{
|
||||||
wxFileName::Assign(path, wxEmptyString);
|
wxFileName::Assign(path, wxEmptyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assign(const wxDirName &path)
|
void Assign(const wxDirName& path)
|
||||||
{
|
{
|
||||||
wxFileName::Assign(path);
|
wxFileName::Assign(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() { wxFileName::Clear(); }
|
void Clear() { wxFileName::Clear(); }
|
||||||
|
|
||||||
wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); }
|
wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); }
|
||||||
wxCharBuffer ToAscii() const { return GetPath().ToAscii(); }
|
wxCharBuffer ToAscii() const { return GetPath().ToAscii(); }
|
||||||
wxString ToString() const { return GetPath(); }
|
wxString ToString() const { return GetPath(); }
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
bool IsWritable() const { return IsDirWritable(); }
|
bool IsWritable() const { return IsDirWritable(); }
|
||||||
bool IsReadable() const { return IsDirReadable(); }
|
bool IsReadable() const { return IsDirReadable(); }
|
||||||
bool Exists() const { return DirExists(); }
|
bool Exists() const { return DirExists(); }
|
||||||
bool FileExists() const { return wxFileName::FileExists(); }
|
bool FileExists() const { return wxFileName::FileExists(); }
|
||||||
bool IsOk() const { return wxFileName::IsOk(); }
|
bool IsOk() const { return wxFileName::IsOk(); }
|
||||||
bool IsRelative() const { return wxFileName::IsRelative(); }
|
bool IsRelative() const { return wxFileName::IsRelative(); }
|
||||||
bool IsAbsolute() const { return wxFileName::IsAbsolute(); }
|
bool IsAbsolute() const { return wxFileName::IsAbsolute(); }
|
||||||
|
|
||||||
bool SameAs(const wxDirName &filepath) const
|
bool SameAs(const wxDirName& filepath) const
|
||||||
{
|
{
|
||||||
return wxFileName::SameAs(filepath);
|
return wxFileName::SameAs(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns true if the file is somewhere inside this directory (and both file and directory are not relative).
|
//Returns true if the file is somewhere inside this directory (and both file and directory are not relative).
|
||||||
bool IsContains(const wxFileName &file) const
|
bool IsContains(const wxFileName& file) const
|
||||||
{
|
{
|
||||||
if (this->IsRelative() || file.IsRelative())
|
if (this->IsRelative() || file.IsRelative())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
wxFileName f(file);
|
wxFileName f(file);
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
if (this->SameAs(wxDirName(f.GetPath())))
|
{
|
||||||
return true;
|
if (this->SameAs(wxDirName(f.GetPath())))
|
||||||
|
return true;
|
||||||
|
|
||||||
if (f.GetDirCount() == 0)
|
if (f.GetDirCount() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
f.RemoveLastDir();
|
f.RemoveLastDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsContains(const wxDirName &dir) const
|
bool IsContains(const wxDirName& dir) const
|
||||||
{
|
{
|
||||||
return IsContains((wxFileName)dir);
|
return IsContains((wxFileName)dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Auto relative works as follows:
|
//Auto relative works as follows:
|
||||||
// 1. if either base or subject are relative, return subject (should never be used with relative paths).
|
// 1. if either base or subject are relative, return subject (should never be used with relative paths).
|
||||||
// 2. else if subject is somewhere inside base folder, then result is subject relative to base.
|
// 2. else if subject is somewhere inside base folder, then result is subject relative to base.
|
||||||
// 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter.
|
// 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter.
|
||||||
// 4. else, result is absolute path of subject.
|
// 4. else, result is absolute path of subject.
|
||||||
//
|
//
|
||||||
// returns ok if both this and base are absolute paths.
|
// returns ok if both this and base are absolute paths.
|
||||||
static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString &pathbase)
|
static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString& pathbase)
|
||||||
{
|
{
|
||||||
wxFileName subject(_subject);
|
wxFileName subject(_subject);
|
||||||
wxDirName base(pathbase);
|
wxDirName base(pathbase);
|
||||||
if (base.IsRelative() || subject.IsRelative())
|
if (base.IsRelative() || subject.IsRelative())
|
||||||
return subject.GetFullPath();
|
return subject.GetFullPath();
|
||||||
|
|
||||||
wxString bv(base.GetVolume());
|
wxString bv(base.GetVolume());
|
||||||
bv.MakeUpper();
|
bv.MakeUpper();
|
||||||
wxString sv(subject.GetVolume());
|
wxString sv(subject.GetVolume());
|
||||||
sv.MakeUpper();
|
sv.MakeUpper();
|
||||||
|
|
||||||
if (base.IsContains(subject)) {
|
if (base.IsContains(subject))
|
||||||
subject.MakeRelativeTo(base.GetFullPath());
|
{
|
||||||
} else if (base.HasVolume() && subject.HasVolume() && bv == sv) {
|
subject.MakeRelativeTo(base.GetFullPath());
|
||||||
wxString unusedVolume;
|
}
|
||||||
wxString pathSansVolume;
|
else if (base.HasVolume() && subject.HasVolume() && bv == sv)
|
||||||
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
{
|
||||||
subject = pathSansVolume;
|
wxString unusedVolume;
|
||||||
}
|
wxString pathSansVolume;
|
||||||
//implicit else: this stays fully absolute
|
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
||||||
|
subject = pathSansVolume;
|
||||||
|
}
|
||||||
|
//implicit else: this stays fully absolute
|
||||||
|
|
||||||
return subject.GetFullPath();
|
return subject.GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString &pathbase)
|
static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString& pathbase)
|
||||||
{
|
{
|
||||||
return MakeAutoRelativeTo(wxFileName(subject), pathbase);
|
return MakeAutoRelativeTo(wxFileName(subject), pathbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of sub folders in this directory path
|
// Returns the number of sub folders in this directory path
|
||||||
size_t GetCount() const { return GetDirCount(); }
|
size_t GetCount() const { return GetDirCount(); }
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
wxFileName Combine(const wxFileName &right) const;
|
wxFileName Combine(const wxFileName& right) const;
|
||||||
wxDirName Combine(const wxDirName &right) const;
|
wxDirName Combine(const wxDirName& right) const;
|
||||||
|
|
||||||
// removes the lastmost directory from the path
|
// removes the lastmost directory from the path
|
||||||
void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); }
|
void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); }
|
||||||
|
|
||||||
wxDirName &Normalize(int flags = wxPATH_NORM_ALL, const wxString &cwd = wxEmptyString);
|
wxDirName& Normalize(int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString);
|
||||||
wxDirName &MakeRelativeTo(const wxString &pathBase = wxEmptyString);
|
wxDirName& MakeRelativeTo(const wxString& pathBase = wxEmptyString);
|
||||||
wxDirName &MakeAbsolute(const wxString &cwd = wxEmptyString);
|
wxDirName& MakeAbsolute(const wxString& cwd = wxEmptyString);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
void AssignCwd(const wxString &volume = wxEmptyString) { wxFileName::AssignCwd(volume); }
|
void AssignCwd(const wxString& volume = wxEmptyString) { wxFileName::AssignCwd(volume); }
|
||||||
bool SetCwd() { return wxFileName::SetCwd(); }
|
bool SetCwd() { return wxFileName::SetCwd(); }
|
||||||
|
|
||||||
// wxWidgets is missing the const qualifier for this one! Shame!
|
// wxWidgets is missing the const qualifier for this one! Shame!
|
||||||
void Rmdir();
|
void Rmdir();
|
||||||
bool Mkdir();
|
bool Mkdir();
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
wxDirName &operator=(const wxDirName &dirname)
|
wxDirName& operator=(const wxDirName& dirname)
|
||||||
{
|
{
|
||||||
Assign(dirname);
|
Assign(dirname);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wxDirName &operator=(const wxString &dirname)
|
wxDirName& operator=(const wxString& dirname)
|
||||||
{
|
{
|
||||||
Assign(dirname);
|
Assign(dirname);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wxDirName &operator=(const char *dirname)
|
wxDirName& operator=(const char* dirname)
|
||||||
{
|
{
|
||||||
Assign(fromUTF8(dirname));
|
Assign(fromUTF8(dirname));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileName operator+(const wxFileName &right) const { return Combine(right); }
|
wxFileName operator+(const wxFileName& right) const { return Combine(right); }
|
||||||
wxDirName operator+(const wxDirName &right) const { return Combine(right); }
|
wxDirName operator+(const wxDirName& right) const { return Combine(right); }
|
||||||
wxFileName operator+(const wxString &right) const { return Combine(wxFileName(right)); }
|
wxFileName operator+(const wxString& right) const { return Combine(wxFileName(right)); }
|
||||||
wxFileName operator+(const char *right) const { return Combine(wxFileName(fromUTF8(right))); }
|
wxFileName operator+(const char* right) const { return Combine(wxFileName(fromUTF8(right))); }
|
||||||
|
|
||||||
bool operator==(const wxDirName &filename) const { return SameAs(filename); }
|
bool operator==(const wxDirName& filename) const { return SameAs(filename); }
|
||||||
bool operator!=(const wxDirName &filename) const { return !SameAs(filename); }
|
bool operator!=(const wxDirName& filename) const { return !SameAs(filename); }
|
||||||
|
|
||||||
bool operator==(const wxFileName &filename) const { return SameAs(wxDirName(filename)); }
|
bool operator==(const wxFileName& filename) const { return SameAs(wxDirName(filename)); }
|
||||||
bool operator!=(const wxFileName &filename) const { return !SameAs(wxDirName(filename)); }
|
bool operator!=(const wxFileName& filename) const { return !SameAs(wxDirName(filename)); }
|
||||||
|
|
||||||
// compare with a filename string interpreted as a native file name
|
// compare with a filename string interpreted as a native file name
|
||||||
bool operator==(const wxString &filename) const { return SameAs(wxDirName(filename)); }
|
bool operator==(const wxString& filename) const { return SameAs(wxDirName(filename)); }
|
||||||
bool operator!=(const wxString &filename) const { return !SameAs(wxDirName(filename)); }
|
bool operator!=(const wxString& filename) const { return !SameAs(wxDirName(filename)); }
|
||||||
|
|
||||||
const wxFileName &GetFilename() const { return *this; }
|
const wxFileName& GetFilename() const { return *this; }
|
||||||
wxFileName &GetFilename() { return *this; }
|
wxFileName& GetFilename() { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -211,20 +215,20 @@ public:
|
||||||
//
|
//
|
||||||
namespace Path
|
namespace Path
|
||||||
{
|
{
|
||||||
extern bool IsRelative(const wxString &path);
|
extern bool IsRelative(const wxString& path);
|
||||||
extern s64 GetFileSize(const wxString &path);
|
extern s64 GetFileSize(const wxString& path);
|
||||||
|
|
||||||
extern wxString Normalize(const wxString &srcpath);
|
extern wxString Normalize(const wxString& srcpath);
|
||||||
extern wxString Normalize(const wxDirName &srcpath);
|
extern wxString Normalize(const wxDirName& srcpath);
|
||||||
extern wxString MakeAbsolute(const wxString &srcpath);
|
extern wxString MakeAbsolute(const wxString& srcpath);
|
||||||
|
|
||||||
extern wxString Combine(const wxString &srcPath, const wxString &srcFile);
|
extern wxString Combine(const wxString& srcPath, const wxString& srcFile);
|
||||||
extern wxString Combine(const wxDirName &srcPath, const wxFileName &srcFile);
|
extern wxString Combine(const wxDirName& srcPath, const wxFileName& srcFile);
|
||||||
extern wxString Combine(const wxString &srcPath, const wxDirName &srcFile);
|
extern wxString Combine(const wxString& srcPath, const wxDirName& srcFile);
|
||||||
extern wxString ReplaceExtension(const wxString &src, const wxString &ext);
|
extern wxString ReplaceExtension(const wxString& src, const wxString& ext);
|
||||||
extern wxString ReplaceFilename(const wxString &src, const wxString &newfilename);
|
extern wxString ReplaceFilename(const wxString& src, const wxString& newfilename);
|
||||||
extern wxString GetFilename(const wxString &src);
|
extern wxString GetFilename(const wxString& src);
|
||||||
extern wxString GetDirectory(const wxString &src);
|
extern wxString GetDirectory(const wxString& src);
|
||||||
extern wxString GetFilenameWithoutExt(const wxString &src);
|
extern wxString GetFilenameWithoutExt(const wxString& src);
|
||||||
extern wxString GetRootDirectory(const wxString &src);
|
extern wxString GetRootDirectory(const wxString& src);
|
||||||
}
|
} // namespace Path
|
||||||
|
|
|
@ -22,60 +22,60 @@
|
||||||
// wxDirName (implementations)
|
// wxDirName (implementations)
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
wxFileName wxDirName::Combine(const wxFileName &right) const
|
wxFileName wxDirName::Combine(const wxFileName& right) const
|
||||||
{
|
{
|
||||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
|
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
|
||||||
if (right.IsAbsolute())
|
if (right.IsAbsolute())
|
||||||
return right;
|
return right;
|
||||||
|
|
||||||
// Append any directory parts from right, and then set the filename.
|
// Append any directory parts from right, and then set the filename.
|
||||||
// Except we can't do that because our m_members are private (argh!) and there is no API
|
// Except we can't do that because our m_members are private (argh!) and there is no API
|
||||||
// for getting each component of the path. So instead let's use Normalize:
|
// for getting each component of the path. So instead let's use Normalize:
|
||||||
|
|
||||||
wxFileName result(right);
|
wxFileName result(right);
|
||||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDirName wxDirName::Combine(const wxDirName &right) const
|
wxDirName wxDirName::Combine(const wxDirName& right) const
|
||||||
{
|
{
|
||||||
pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation.");
|
pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation.");
|
||||||
|
|
||||||
wxDirName result(right);
|
wxDirName result(right);
|
||||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDirName &wxDirName::Normalize(int flags, const wxString &cwd)
|
wxDirName& wxDirName::Normalize(int flags, const wxString& cwd)
|
||||||
{
|
{
|
||||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||||
if (!wxFileName::Normalize(flags, cwd))
|
if (!wxFileName::Normalize(flags, cwd))
|
||||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
|
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDirName &wxDirName::MakeRelativeTo(const wxString &pathBase)
|
wxDirName& wxDirName::MakeRelativeTo(const wxString& pathBase)
|
||||||
{
|
{
|
||||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||||
if (!wxFileName::MakeRelativeTo(pathBase))
|
if (!wxFileName::MakeRelativeTo(pathBase))
|
||||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
|
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDirName &wxDirName::MakeAbsolute(const wxString &cwd)
|
wxDirName& wxDirName::MakeAbsolute(const wxString& cwd)
|
||||||
{
|
{
|
||||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||||
if (!wxFileName::MakeAbsolute(cwd))
|
if (!wxFileName::MakeAbsolute(cwd))
|
||||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
|
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxDirName::Rmdir()
|
void wxDirName::Rmdir()
|
||||||
{
|
{
|
||||||
if (!Exists())
|
if (!Exists())
|
||||||
return;
|
return;
|
||||||
wxFileName::Rmdir();
|
wxFileName::Rmdir();
|
||||||
// TODO : Throw exception if operation failed? Do we care?
|
// TODO : Throw exception if operation failed? Do we care?
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxDirName::Mkdir()
|
bool wxDirName::Mkdir()
|
||||||
|
@ -87,9 +87,9 @@ bool wxDirName::Mkdir()
|
||||||
#define wxS_DIR_DEFAULT 0777
|
#define wxS_DIR_DEFAULT 0777
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (Exists())
|
if (Exists())
|
||||||
return true;
|
return true;
|
||||||
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
|
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,111 +98,111 @@ bool wxDirName::Mkdir()
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
bool Path::IsRelative(const wxString &path)
|
bool Path::IsRelative(const wxString& path)
|
||||||
{
|
{
|
||||||
return wxDirName(path).IsRelative();
|
return wxDirName(path).IsRelative();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns -1 if the file does not exist.
|
// Returns -1 if the file does not exist.
|
||||||
s64 Path::GetFileSize(const wxString &path)
|
s64 Path::GetFileSize(const wxString& path)
|
||||||
{
|
{
|
||||||
if (!wxFile::Exists(path.c_str()))
|
if (!wxFile::Exists(path.c_str()))
|
||||||
return -1;
|
return -1;
|
||||||
return (s64)wxFileName::GetSize(path).GetValue();
|
return (s64)wxFileName::GetSize(path).GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString Path::Normalize(const wxString &src)
|
wxString Path::Normalize(const wxString& src)
|
||||||
{
|
{
|
||||||
wxFileName normalize(src);
|
wxFileName normalize(src);
|
||||||
normalize.Normalize();
|
normalize.Normalize();
|
||||||
return normalize.GetFullPath();
|
return normalize.GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::Normalize(const wxDirName &src)
|
wxString Path::Normalize(const wxDirName& src)
|
||||||
{
|
{
|
||||||
return wxDirName(src).Normalize().ToString();
|
return wxDirName(src).Normalize().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::MakeAbsolute(const wxString &src)
|
wxString Path::MakeAbsolute(const wxString& src)
|
||||||
{
|
{
|
||||||
wxFileName absolute(src);
|
wxFileName absolute(src);
|
||||||
absolute.MakeAbsolute();
|
absolute.MakeAbsolute();
|
||||||
return absolute.GetFullPath();
|
return absolute.GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenates two pathnames together, inserting delimiters (backslash on win32)
|
// Concatenates two pathnames together, inserting delimiters (backslash on win32)
|
||||||
// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length.
|
// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length.
|
||||||
//
|
//
|
||||||
wxString Path::Combine(const wxString &srcPath, const wxString &srcFile)
|
wxString Path::Combine(const wxString& srcPath, const wxString& srcFile)
|
||||||
{
|
{
|
||||||
return (wxDirName(srcPath) + srcFile).GetFullPath();
|
return (wxDirName(srcPath) + srcFile).GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::Combine(const wxDirName &srcPath, const wxFileName &srcFile)
|
wxString Path::Combine(const wxDirName& srcPath, const wxFileName& srcFile)
|
||||||
{
|
{
|
||||||
return (srcPath + srcFile).GetFullPath();
|
return (srcPath + srcFile).GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::Combine(const wxString &srcPath, const wxDirName &srcFile)
|
wxString Path::Combine(const wxString& srcPath, const wxDirName& srcFile)
|
||||||
{
|
{
|
||||||
return (wxDirName(srcPath) + srcFile).ToString();
|
return (wxDirName(srcPath) + srcFile).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces the extension of the file with the one given.
|
// Replaces the extension of the file with the one given.
|
||||||
// This function works for path names as well as file names.
|
// This function works for path names as well as file names.
|
||||||
wxString Path::ReplaceExtension(const wxString &src, const wxString &ext)
|
wxString Path::ReplaceExtension(const wxString& src, const wxString& ext)
|
||||||
{
|
{
|
||||||
wxFileName jojo(src);
|
wxFileName jojo(src);
|
||||||
jojo.SetExt(ext);
|
jojo.SetExt(ext);
|
||||||
return jojo.GetFullPath();
|
return jojo.GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::ReplaceFilename(const wxString &src, const wxString &newfilename)
|
wxString Path::ReplaceFilename(const wxString& src, const wxString& newfilename)
|
||||||
{
|
{
|
||||||
wxFileName jojo(src);
|
wxFileName jojo(src);
|
||||||
jojo.SetFullName(newfilename);
|
jojo.SetFullName(newfilename);
|
||||||
return jojo.GetFullPath();
|
return jojo.GetFullPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::GetFilename(const wxString &src)
|
wxString Path::GetFilename(const wxString& src)
|
||||||
{
|
{
|
||||||
return wxFileName(src).GetFullName();
|
return wxFileName(src).GetFullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::GetFilenameWithoutExt(const wxString &src)
|
wxString Path::GetFilenameWithoutExt(const wxString& src)
|
||||||
{
|
{
|
||||||
return wxFileName(src).GetName();
|
return wxFileName(src).GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Path::GetDirectory(const wxString &src)
|
wxString Path::GetDirectory(const wxString& src)
|
||||||
{
|
{
|
||||||
return wxFileName(src).GetPath();
|
return wxFileName(src).GetPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns the base/root directory of the given path.
|
// returns the base/root directory of the given path.
|
||||||
// Example /this/that/something.txt -> dest == "/"
|
// Example /this/that/something.txt -> dest == "/"
|
||||||
wxString Path::GetRootDirectory(const wxString &src)
|
wxString Path::GetRootDirectory(const wxString& src)
|
||||||
{
|
{
|
||||||
size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
|
size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
|
||||||
if (pos == wxString::npos)
|
if (pos == wxString::npos)
|
||||||
return wxString();
|
return wxString();
|
||||||
else
|
else
|
||||||
return wxString(src.begin(), src.begin() + pos);
|
return wxString(src.begin(), src.begin() + pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Launches the specified file according to its mime type
|
// Launches the specified file according to its mime type
|
||||||
//
|
//
|
||||||
void pxLaunch(const wxString &filename)
|
void pxLaunch(const wxString& filename)
|
||||||
{
|
{
|
||||||
wxLaunchDefaultBrowser(filename);
|
wxLaunchDefaultBrowser(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxLaunch(const char *filename)
|
void pxLaunch(const char* filename)
|
||||||
{
|
{
|
||||||
pxLaunch(fromUTF8(filename));
|
pxLaunch(fromUTF8(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -211,12 +211,12 @@ void pxLaunch(const char *filename)
|
||||||
// bypasses wxWidgets internal filename checking, which can end up launching things
|
// bypasses wxWidgets internal filename checking, which can end up launching things
|
||||||
// through browser more often than desired.
|
// through browser more often than desired.
|
||||||
//
|
//
|
||||||
void pxExplore(const wxString &path)
|
void pxExplore(const wxString& path)
|
||||||
{
|
{
|
||||||
wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path);
|
wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxExplore(const char *path)
|
void pxExplore(const char* path)
|
||||||
{
|
{
|
||||||
pxExplore(fromUTF8(path));
|
pxExplore(fromUTF8(path));
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,116 +60,116 @@ typedef unsigned int uint;
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
union u128
|
union u128
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u64 lo;
|
u64 lo;
|
||||||
u64 hi;
|
u64 hi;
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 _u64[2];
|
u64 _u64[2];
|
||||||
u32 _u32[4];
|
u32 _u32[4];
|
||||||
u16 _u16[8];
|
u16 _u16[8];
|
||||||
u8 _u8[16];
|
u8 _u8[16];
|
||||||
|
|
||||||
// Explicit conversion from u64. Zero-extends the source through 128 bits.
|
// Explicit conversion from u64. Zero-extends the source through 128 bits.
|
||||||
static u128 From64(u64 src)
|
static u128 From64(u64 src)
|
||||||
{
|
{
|
||||||
u128 retval;
|
u128 retval;
|
||||||
retval.lo = src;
|
retval.lo = src;
|
||||||
retval.hi = 0;
|
retval.hi = 0;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicit conversion from u32. Zero-extends the source through 128 bits.
|
// Explicit conversion from u32. Zero-extends the source through 128 bits.
|
||||||
static u128 From32(u32 src)
|
static u128 From32(u32 src)
|
||||||
{
|
{
|
||||||
u128 retval;
|
u128 retval;
|
||||||
retval._u32[0] = src;
|
retval._u32[0] = src;
|
||||||
retval._u32[1] = 0;
|
retval._u32[1] = 0;
|
||||||
retval.hi = 0;
|
retval.hi = 0;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator u32() const { return _u32[0]; }
|
operator u32() const { return _u32[0]; }
|
||||||
operator u16() const { return _u16[0]; }
|
operator u16() const { return _u16[0]; }
|
||||||
operator u8() const { return _u8[0]; }
|
operator u8() const { return _u8[0]; }
|
||||||
|
|
||||||
bool operator==(const u128 &right) const
|
bool operator==(const u128& right) const
|
||||||
{
|
{
|
||||||
return (lo == right.lo) && (hi == right.hi);
|
return (lo == right.lo) && (hi == right.hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const u128 &right) const
|
bool operator!=(const u128& right) const
|
||||||
{
|
{
|
||||||
return (lo != right.lo) || (hi != right.hi);
|
return (lo != right.lo) || (hi != right.hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order for the following ToString() and WriteTo methods to be available, you must
|
// In order for the following ToString() and WriteTo methods to be available, you must
|
||||||
// be linking to both wxWidgets and the pxWidgets extension library. If you are not
|
// be linking to both wxWidgets and the pxWidgets extension library. If you are not
|
||||||
// using them, then you will need to provide your own implementations of these methods.
|
// using them, then you will need to provide your own implementations of these methods.
|
||||||
wxString ToString() const;
|
wxString ToString() const;
|
||||||
wxString ToString64() const;
|
wxString ToString64() const;
|
||||||
wxString ToString8() const;
|
wxString ToString8() const;
|
||||||
|
|
||||||
void WriteTo(FastFormatAscii &dest) const;
|
void WriteTo(FastFormatAscii& dest) const;
|
||||||
void WriteTo8(FastFormatAscii &dest) const;
|
void WriteTo8(FastFormatAscii& dest) const;
|
||||||
void WriteTo64(FastFormatAscii &dest) const;
|
void WriteTo64(FastFormatAscii& dest) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s128
|
struct s128
|
||||||
{
|
{
|
||||||
s64 lo;
|
s64 lo;
|
||||||
s64 hi;
|
s64 hi;
|
||||||
|
|
||||||
// explicit conversion from s64, with sign extension.
|
// explicit conversion from s64, with sign extension.
|
||||||
static s128 From64(s64 src)
|
static s128 From64(s64 src)
|
||||||
{
|
{
|
||||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicit conversion from s32, with sign extension.
|
// explicit conversion from s32, with sign extension.
|
||||||
static s128 From64(s32 src)
|
static s128 From64(s32 src)
|
||||||
{
|
{
|
||||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator u32() const { return (s32)lo; }
|
operator u32() const { return (s32)lo; }
|
||||||
operator u16() const { return (s16)lo; }
|
operator u16() const { return (s16)lo; }
|
||||||
operator u8() const { return (s8)lo; }
|
operator u8() const { return (s8)lo; }
|
||||||
|
|
||||||
bool operator==(const s128 &right) const
|
bool operator==(const s128& right) const
|
||||||
{
|
{
|
||||||
return (lo == right.lo) && (hi == right.hi);
|
return (lo == right.lo) && (hi == right.hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const s128 &right) const
|
bool operator!=(const s128& right) const
|
||||||
{
|
{
|
||||||
return (lo != right.lo) || (hi != right.hi);
|
return (lo != right.lo) || (hi != right.hi);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
typedef union _u128_t
|
typedef union _u128_t
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u64 lo;
|
u64 lo;
|
||||||
u64 hi;
|
u64 hi;
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 _u64[2];
|
u64 _u64[2];
|
||||||
u32 _u32[4];
|
u32 _u32[4];
|
||||||
u16 _u16[8];
|
u16 _u16[8];
|
||||||
u8 _u8[16];
|
u8 _u8[16];
|
||||||
} u128;
|
} u128;
|
||||||
|
|
||||||
typedef union _s128_t
|
typedef union _s128_t
|
||||||
{
|
{
|
||||||
u64 lo;
|
u64 lo;
|
||||||
s64 hi;
|
s64 hi;
|
||||||
} s128;
|
} s128;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
225
common/Perf.cpp
225
common/Perf.cpp
|
@ -33,174 +33,175 @@
|
||||||
|
|
||||||
namespace Perf
|
namespace Perf
|
||||||
{
|
{
|
||||||
// Warning object aren't thread safe
|
// Warning object aren't thread safe
|
||||||
InfoVector any("");
|
InfoVector any("");
|
||||||
InfoVector ee("EE");
|
InfoVector ee("EE");
|
||||||
InfoVector iop("IOP");
|
InfoVector iop("IOP");
|
||||||
InfoVector vu("VU");
|
InfoVector vu("VU");
|
||||||
InfoVector vif("VIF");
|
InfoVector vif("VIF");
|
||||||
|
|
||||||
// Perf is only supported on linux
|
// Perf is only supported on linux
|
||||||
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
|
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Implementation of the Info object
|
// Implementation of the Info object
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Info::Info(uptr x86, u32 size, const char *symbol)
|
Info::Info(uptr x86, u32 size, const char* symbol)
|
||||||
: m_x86(x86)
|
: m_x86(x86)
|
||||||
, m_size(size)
|
, m_size(size)
|
||||||
, m_dynamic(false)
|
, m_dynamic(false)
|
||||||
{
|
{
|
||||||
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
Info::Info(uptr x86, u32 size, const char *symbol, u32 pc)
|
Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
|
||||||
: m_x86(x86)
|
: m_x86(x86)
|
||||||
, m_size(size)
|
, m_size(size)
|
||||||
, m_dynamic(true)
|
, m_dynamic(true)
|
||||||
{
|
{
|
||||||
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Info::Print(FILE *fp)
|
void Info::Print(FILE* fp)
|
||||||
{
|
{
|
||||||
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Implementation of the InfoVector object
|
// Implementation of the InfoVector object
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
InfoVector::InfoVector(const char *prefix)
|
InfoVector::InfoVector(const char* prefix)
|
||||||
{
|
{
|
||||||
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
||||||
#ifdef ENABLE_VTUNE
|
#ifdef ENABLE_VTUNE
|
||||||
m_vtune_id = iJIT_GetNewMethodID();
|
m_vtune_id = iJIT_GetNewMethodID();
|
||||||
#else
|
#else
|
||||||
m_vtune_id = 0;
|
m_vtune_id = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoVector::print(FILE *fp)
|
void InfoVector::print(FILE* fp)
|
||||||
{
|
{
|
||||||
for (auto &&it : m_v)
|
for (auto&& it : m_v)
|
||||||
it.Print(fp);
|
it.Print(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoVector::map(uptr x86, u32 size, const char *symbol)
|
void InfoVector::map(uptr x86, u32 size, const char* symbol)
|
||||||
{
|
{
|
||||||
// This function is typically used for dispatcher and recompiler.
|
// This function is typically used for dispatcher and recompiler.
|
||||||
// Dispatchers are on a page and must always be kept.
|
// Dispatchers are on a page and must always be kept.
|
||||||
// Recompilers are much bigger (TODO check VIF) and are only
|
// Recompilers are much bigger (TODO check VIF) and are only
|
||||||
// useful when MERGE_BLOCK_RESULT is defined
|
// useful when MERGE_BLOCK_RESULT is defined
|
||||||
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
|
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
|
||||||
u32 max_code_size = 16 * _1kb;
|
u32 max_code_size = 16 * _1kb;
|
||||||
#else
|
#else
|
||||||
u32 max_code_size = _1gb;
|
u32 max_code_size = _1gb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (size < max_code_size) {
|
if (size < max_code_size)
|
||||||
m_v.emplace_back(x86, size, symbol);
|
{
|
||||||
|
m_v.emplace_back(x86, size, symbol);
|
||||||
|
|
||||||
#ifdef ENABLE_VTUNE
|
#ifdef ENABLE_VTUNE
|
||||||
std::string name = std::string(symbol);
|
std::string name = std::string(symbol);
|
||||||
|
|
||||||
iJIT_Method_Load ml;
|
iJIT_Method_Load ml;
|
||||||
|
|
||||||
memset(&ml, 0, sizeof(ml));
|
memset(&ml, 0, sizeof(ml));
|
||||||
|
|
||||||
ml.method_id = iJIT_GetNewMethodID();
|
ml.method_id = iJIT_GetNewMethodID();
|
||||||
ml.method_name = (char *)name.c_str();
|
ml.method_name = (char*)name.c_str();
|
||||||
ml.method_load_address = (void *)x86;
|
ml.method_load_address = (void*)x86;
|
||||||
ml.method_size = size;
|
ml.method_size = size;
|
||||||
|
|
||||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
||||||
|
|
||||||
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
|
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
||||||
{
|
{
|
||||||
#ifndef MERGE_BLOCK_RESULT
|
#ifndef MERGE_BLOCK_RESULT
|
||||||
m_v.emplace_back(x86, size, m_prefix, pc);
|
m_v.emplace_back(x86, size, m_prefix, pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_VTUNE
|
#ifdef ENABLE_VTUNE
|
||||||
iJIT_Method_Load_V2 ml;
|
iJIT_Method_Load_V2 ml;
|
||||||
|
|
||||||
memset(&ml, 0, sizeof(ml));
|
memset(&ml, 0, sizeof(ml));
|
||||||
|
|
||||||
#ifdef MERGE_BLOCK_RESULT
|
#ifdef MERGE_BLOCK_RESULT
|
||||||
ml.method_id = m_vtune_id;
|
ml.method_id = m_vtune_id;
|
||||||
ml.method_name = m_prefix;
|
ml.method_name = m_prefix;
|
||||||
#else
|
#else
|
||||||
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
||||||
ml.method_id = iJIT_GetNewMethodID();
|
ml.method_id = iJIT_GetNewMethodID();
|
||||||
ml.method_name = (char *)name.c_str();
|
ml.method_name = (char*)name.c_str();
|
||||||
#endif
|
#endif
|
||||||
ml.method_load_address = (void *)x86;
|
ml.method_load_address = (void*)x86;
|
||||||
ml.method_size = size;
|
ml.method_size = size;
|
||||||
|
|
||||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||||
|
|
||||||
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
|
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoVector::reset()
|
void InfoVector::reset()
|
||||||
{
|
{
|
||||||
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
||||||
m_v.erase(dynamic, m_v.end());
|
m_v.erase(dynamic, m_v.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Global function
|
// Global function
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void dump()
|
void dump()
|
||||||
{
|
{
|
||||||
char file[256];
|
char file[256];
|
||||||
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
||||||
FILE *fp = fopen(file, "w");
|
FILE* fp = fopen(file, "w");
|
||||||
|
|
||||||
any.print(fp);
|
any.print(fp);
|
||||||
ee.print(fp);
|
ee.print(fp);
|
||||||
iop.print(fp);
|
iop.print(fp);
|
||||||
vu.print(fp);
|
vu.print(fp);
|
||||||
|
|
||||||
if (fp)
|
if (fp)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_and_reset()
|
void dump_and_reset()
|
||||||
{
|
{
|
||||||
dump();
|
dump();
|
||||||
|
|
||||||
any.reset();
|
any.reset();
|
||||||
ee.reset();
|
ee.reset();
|
||||||
iop.reset();
|
iop.reset();
|
||||||
vu.reset();
|
vu.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Dummy implementation
|
// Dummy implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
InfoVector::InfoVector(const char *prefix)
|
InfoVector::InfoVector(const char* prefix)
|
||||||
: m_vtune_id(0)
|
: m_vtune_id(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void InfoVector::map(uptr x86, u32 size, const char *symbol) {}
|
void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
|
||||||
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
||||||
void InfoVector::reset() {}
|
void InfoVector::reset() {}
|
||||||
|
|
||||||
void dump() {}
|
void dump() {}
|
||||||
void dump_and_reset() {}
|
void dump_and_reset() {}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace Perf
|
||||||
|
|
|
@ -22,41 +22,41 @@
|
||||||
namespace Perf
|
namespace Perf
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Info
|
struct Info
|
||||||
{
|
{
|
||||||
uptr m_x86;
|
uptr m_x86;
|
||||||
u32 m_size;
|
u32 m_size;
|
||||||
char m_symbol[20];
|
char m_symbol[20];
|
||||||
// The idea is to keep static zones that are set only
|
// The idea is to keep static zones that are set only
|
||||||
// once.
|
// once.
|
||||||
bool m_dynamic;
|
bool m_dynamic;
|
||||||
|
|
||||||
Info(uptr x86, u32 size, const char *symbol);
|
Info(uptr x86, u32 size, const char* symbol);
|
||||||
Info(uptr x86, u32 size, const char *symbol, u32 pc);
|
Info(uptr x86, u32 size, const char* symbol, u32 pc);
|
||||||
void Print(FILE *fp);
|
void Print(FILE* fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
class InfoVector
|
class InfoVector
|
||||||
{
|
{
|
||||||
std::vector<Info> m_v;
|
std::vector<Info> m_v;
|
||||||
char m_prefix[20];
|
char m_prefix[20];
|
||||||
unsigned int m_vtune_id;
|
unsigned int m_vtune_id;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InfoVector(const char *prefix);
|
InfoVector(const char* prefix);
|
||||||
|
|
||||||
void print(FILE *fp);
|
void print(FILE* fp);
|
||||||
void map(uptr x86, u32 size, const char *symbol);
|
void map(uptr x86, u32 size, const char* symbol);
|
||||||
void map(uptr x86, u32 size, u32 pc);
|
void map(uptr x86, u32 size, u32 pc);
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
void dump();
|
void dump();
|
||||||
void dump_and_reset();
|
void dump_and_reset();
|
||||||
|
|
||||||
extern InfoVector any;
|
extern InfoVector any;
|
||||||
extern InfoVector ee;
|
extern InfoVector ee;
|
||||||
extern InfoVector iop;
|
extern InfoVector iop;
|
||||||
extern InfoVector vu;
|
extern InfoVector vu;
|
||||||
extern InfoVector vif;
|
extern InfoVector vif;
|
||||||
}
|
} // namespace Perf
|
||||||
|
|
|
@ -22,188 +22,188 @@
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ThreadDeleteEvent
|
// ThreadDeleteEvent
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class EventListener_Thread : public IEventDispatcher<int>
|
class EventListener_Thread : public IEventDispatcher<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef int EvtParams;
|
typedef int EvtParams;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
pxThread *m_thread;
|
pxThread* m_thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EventListener_Thread()
|
EventListener_Thread()
|
||||||
{
|
{
|
||||||
m_thread = NULL;
|
m_thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~EventListener_Thread() = default;
|
virtual ~EventListener_Thread() = default;
|
||||||
|
|
||||||
void SetThread(pxThread &thr) { m_thread = &thr; }
|
void SetThread(pxThread& thr) { m_thread = &thr; }
|
||||||
void SetThread(pxThread *thr) { m_thread = thr; }
|
void SetThread(pxThread* thr) { m_thread = thr; }
|
||||||
|
|
||||||
void DispatchEvent(const int ¶ms)
|
void DispatchEvent(const int& params)
|
||||||
{
|
{
|
||||||
OnThreadCleanup();
|
OnThreadCleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Invoked by the pxThread when the thread execution is ending. This is
|
// Invoked by the pxThread when the thread execution is ending. This is
|
||||||
// typically more useful than a delete listener since the extended thread information
|
// typically more useful than a delete listener since the extended thread information
|
||||||
// provided by virtualized functions/methods will be available.
|
// provided by virtualized functions/methods will be available.
|
||||||
// Important! This event is executed *by the thread*, so care must be taken to ensure
|
// Important! This event is executed *by the thread*, so care must be taken to ensure
|
||||||
// thread sync when necessary (posting messages to the main thread, etc).
|
// thread sync when necessary (posting messages to the main thread, etc).
|
||||||
virtual void OnThreadCleanup() = 0;
|
virtual void OnThreadCleanup() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Set the name of the current thread
|
/// Set the name of the current thread
|
||||||
void SetNameOfCurrentThread(const char* name);
|
void SetNameOfCurrentThread(const char* name);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxThread - Helper class for the basics of starting/managing persistent threads.
|
// pxThread - Helper class for the basics of starting/managing persistent threads.
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This class is meant to be a helper for the typical threading model of "start once and
|
// This class is meant to be a helper for the typical threading model of "start once and
|
||||||
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
||||||
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
||||||
// functionality needed for a threaded operation. In practice this model is usually an
|
// functionality needed for a threaded operation. In practice this model is usually an
|
||||||
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
||||||
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
||||||
// new threads has quite a bit of overhead.
|
// new threads has quite a bit of overhead.
|
||||||
//
|
//
|
||||||
// To use this as a base class for your threaded procedure, overload the following virtual
|
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||||
// methods:
|
// methods:
|
||||||
// void OnStart();
|
// void OnStart();
|
||||||
// void ExecuteTaskInThread();
|
// void ExecuteTaskInThread();
|
||||||
// void OnCleanupInThread();
|
// void OnCleanupInThread();
|
||||||
//
|
//
|
||||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||||
// it in your derived class if your thread utilizes the post).
|
// it in your derived class if your thread utilizes the post).
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||||
// no dependency options for ensuring correct static var initializations). Use heap
|
// no dependency options for ensuring correct static var initializations). Use heap
|
||||||
// allocation to create thread objects instead.
|
// allocation to create thread objects instead.
|
||||||
//
|
//
|
||||||
class pxThread
|
class pxThread
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(pxThread);
|
DeclareNoncopyableObject(pxThread);
|
||||||
|
|
||||||
friend void pxYield(int ms);
|
friend void pxYield(int ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_name; // diagnostic name for our thread.
|
wxString m_name; // diagnostic name for our thread.
|
||||||
pthread_t m_thread;
|
pthread_t m_thread;
|
||||||
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
|
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
|
||||||
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
|
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
|
||||||
|
|
||||||
Semaphore m_sem_event; // general wait event that's needed by most threads
|
Semaphore m_sem_event; // general wait event that's needed by most threads
|
||||||
Semaphore m_sem_startup; // startup sync tool
|
Semaphore m_sem_startup; // startup sync tool
|
||||||
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
||||||
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
||||||
Mutex m_mtx_ThreadName;
|
Mutex m_mtx_ThreadName;
|
||||||
|
|
||||||
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
|
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||||
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||||
|
|
||||||
// exception handle, set non-NULL if the thread terminated with an exception
|
// exception handle, set non-NULL if the thread terminated with an exception
|
||||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||||
ScopedPtrMT<BaseException> m_except;
|
ScopedPtrMT<BaseException> m_except;
|
||||||
|
|
||||||
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxThread();
|
virtual ~pxThread();
|
||||||
pxThread(const wxString &name = L"pxThread");
|
pxThread(const wxString& name = L"pxThread");
|
||||||
|
|
||||||
pthread_t GetId() const { return m_thread; }
|
pthread_t GetId() const { return m_thread; }
|
||||||
u64 GetCpuTime() const;
|
u64 GetCpuTime() const;
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void Cancel(bool isBlocking = true);
|
virtual void Cancel(bool isBlocking = true);
|
||||||
virtual bool Cancel(const wxTimeSpan &timeout);
|
virtual bool Cancel(const wxTimeSpan& timeout);
|
||||||
virtual bool Detach();
|
virtual bool Detach();
|
||||||
virtual void Block();
|
virtual void Block();
|
||||||
virtual bool Block(const wxTimeSpan &timeout);
|
virtual bool Block(const wxTimeSpan& timeout);
|
||||||
virtual void RethrowException() const;
|
virtual void RethrowException() const;
|
||||||
|
|
||||||
void AddListener(EventListener_Thread &evt);
|
void AddListener(EventListener_Thread& evt);
|
||||||
void AddListener(EventListener_Thread *evt)
|
void AddListener(EventListener_Thread* evt)
|
||||||
{
|
{
|
||||||
if (evt == NULL)
|
if (evt == NULL)
|
||||||
return;
|
return;
|
||||||
AddListener(*evt);
|
AddListener(*evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitOnSelf(Semaphore &mutex) const;
|
void WaitOnSelf(Semaphore& mutex) const;
|
||||||
void WaitOnSelf(Mutex &mutex) const;
|
void WaitOnSelf(Mutex& mutex) const;
|
||||||
bool WaitOnSelf(Semaphore &mutex, const wxTimeSpan &timeout) const;
|
bool WaitOnSelf(Semaphore& mutex, const wxTimeSpan& timeout) const;
|
||||||
bool WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const;
|
bool WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const;
|
||||||
|
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
bool IsSelf() const;
|
bool IsSelf() const;
|
||||||
bool HasPendingException() const { return !!m_except; }
|
bool HasPendingException() const { return !!m_except; }
|
||||||
|
|
||||||
wxString GetName() const;
|
wxString GetName() const;
|
||||||
void SetName(const wxString &newname);
|
void SetName(const wxString& newname);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Extending classes should always implement your own OnStart(), which is called by
|
// Extending classes should always implement your own OnStart(), which is called by
|
||||||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||||
// unless you're really sure that's what you need to do. ;)
|
// unless you're really sure that's what you need to do. ;)
|
||||||
virtual void OnStart();
|
virtual void OnStart();
|
||||||
|
|
||||||
virtual void OnStartInThread();
|
virtual void OnStartInThread();
|
||||||
|
|
||||||
// This is called when the thread has been canceled or exits normally. The pxThread
|
// This is called when the thread has been canceled or exits normally. The pxThread
|
||||||
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
||||||
virtual void OnCleanupInThread();
|
virtual void OnCleanupInThread();
|
||||||
|
|
||||||
// Implemented by derived class to perform actual threaded task!
|
// Implemented by derived class to perform actual threaded task!
|
||||||
virtual void ExecuteTaskInThread() = 0;
|
virtual void ExecuteTaskInThread() = 0;
|
||||||
|
|
||||||
void TestCancel() const;
|
void TestCancel() const;
|
||||||
|
|
||||||
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
||||||
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
||||||
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
||||||
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
||||||
// timeslice is yielded to other contending threads. If no threads are contending for
|
// timeslice is yielded to other contending threads. If no threads are contending for
|
||||||
// time when ms==0, then no yield is done, but cancellation is still tested.
|
// time when ms==0, then no yield is done, but cancellation is still tested.
|
||||||
void Yield(int ms = 0)
|
void Yield(int ms = 0)
|
||||||
{
|
{
|
||||||
pxAssert(IsSelf());
|
pxAssert(IsSelf());
|
||||||
Threading::Sleep(ms);
|
Threading::Sleep(ms);
|
||||||
TestCancel();
|
TestCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrankenMutex(Mutex &mutex);
|
void FrankenMutex(Mutex& mutex);
|
||||||
|
|
||||||
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const;
|
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const;
|
||||||
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const;
|
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Section of methods for internal use only.
|
// Section of methods for internal use only.
|
||||||
|
|
||||||
void _platform_specific_OnStartInThread();
|
void _platform_specific_OnStartInThread();
|
||||||
void _platform_specific_OnCleanupInThread();
|
void _platform_specific_OnCleanupInThread();
|
||||||
bool _basecancel();
|
bool _basecancel();
|
||||||
void _selfRunningTest(const wxChar *name) const;
|
void _selfRunningTest(const wxChar* name) const;
|
||||||
void _DoSetThreadName(const wxString &name);
|
void _DoSetThreadName(const wxString& name);
|
||||||
void _DoSetThreadName(const char *name) { SetNameOfCurrentThread(name); }
|
void _DoSetThreadName(const char* name) { SetNameOfCurrentThread(name); }
|
||||||
void _internal_execute();
|
void _internal_execute();
|
||||||
void _try_virtual_invoke(void (pxThread::*method)());
|
void _try_virtual_invoke(void (pxThread::*method)());
|
||||||
void _ThreadCleanup();
|
void _ThreadCleanup();
|
||||||
|
|
||||||
static void *_internal_callback(void *func);
|
static void* _internal_callback(void* func);
|
||||||
static void internal_callback_helper(void *func);
|
static void internal_callback_helper(void* func);
|
||||||
static void _pt_callback_cleanup(void *handle);
|
static void _pt_callback_cleanup(void* handle);
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -20,37 +20,37 @@
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Threading::RwMutex::RwMutex()
|
Threading::RwMutex::RwMutex()
|
||||||
{
|
{
|
||||||
pthread_rwlock_init(&m_rwlock, NULL);
|
pthread_rwlock_init(&m_rwlock, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::RwMutex::~RwMutex()
|
Threading::RwMutex::~RwMutex()
|
||||||
{
|
{
|
||||||
pthread_rwlock_destroy(&m_rwlock);
|
pthread_rwlock_destroy(&m_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::RwMutex::AcquireRead()
|
void Threading::RwMutex::AcquireRead()
|
||||||
{
|
{
|
||||||
pthread_rwlock_rdlock(&m_rwlock);
|
pthread_rwlock_rdlock(&m_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::RwMutex::AcquireWrite()
|
void Threading::RwMutex::AcquireWrite()
|
||||||
{
|
{
|
||||||
pthread_rwlock_wrlock(&m_rwlock);
|
pthread_rwlock_wrlock(&m_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::RwMutex::TryAcquireRead()
|
bool Threading::RwMutex::TryAcquireRead()
|
||||||
{
|
{
|
||||||
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
|
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::RwMutex::TryAcquireWrite()
|
bool Threading::RwMutex::TryAcquireWrite()
|
||||||
{
|
{
|
||||||
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
|
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::RwMutex::Release()
|
void Threading::RwMutex::Release()
|
||||||
{
|
{
|
||||||
pthread_rwlock_unlock(&m_rwlock);
|
pthread_rwlock_unlock(&m_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -58,57 +58,57 @@ void Threading::RwMutex::Release()
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock()
|
Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock()
|
||||||
{
|
{
|
||||||
if (m_IsLocked)
|
if (m_IsLocked)
|
||||||
m_lock.Release();
|
m_lock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provides manual unlocking of a scoped lock prior to object destruction.
|
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||||
void Threading::BaseScopedReadWriteLock::Release()
|
void Threading::BaseScopedReadWriteLock::Release()
|
||||||
{
|
{
|
||||||
if (!m_IsLocked)
|
if (!m_IsLocked)
|
||||||
return;
|
return;
|
||||||
m_IsLocked = false;
|
m_IsLocked = false;
|
||||||
m_lock.Release();
|
m_lock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ScopedReadLock / ScopedWriteLock
|
// ScopedReadLock / ScopedWriteLock
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
Threading::ScopedReadLock::ScopedReadLock(RwMutex &locker)
|
Threading::ScopedReadLock::ScopedReadLock(RwMutex& locker)
|
||||||
: BaseScopedReadWriteLock(locker)
|
: BaseScopedReadWriteLock(locker)
|
||||||
{
|
{
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
m_lock.AcquireRead();
|
m_lock.AcquireRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||||
void Threading::ScopedReadLock::Acquire()
|
void Threading::ScopedReadLock::Acquire()
|
||||||
{
|
{
|
||||||
if (m_IsLocked)
|
if (m_IsLocked)
|
||||||
return;
|
return;
|
||||||
m_lock.AcquireRead();
|
m_lock.AcquireRead();
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker)
|
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker)
|
||||||
: BaseScopedReadWriteLock(locker)
|
: BaseScopedReadWriteLock(locker)
|
||||||
{
|
{
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
m_lock.AcquireWrite();
|
m_lock.AcquireWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||||
void Threading::ScopedWriteLock::Acquire()
|
void Threading::ScopedWriteLock::Acquire()
|
||||||
{
|
{
|
||||||
if (m_IsLocked)
|
if (m_IsLocked)
|
||||||
return;
|
return;
|
||||||
m_lock.AcquireWrite();
|
m_lock.AcquireWrite();
|
||||||
m_IsLocked = true;
|
m_IsLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special constructor used by ScopedTryLock
|
// Special constructor used by ScopedTryLock
|
||||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker, bool isTryLock)
|
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker, bool isTryLock)
|
||||||
: BaseScopedReadWriteLock(locker)
|
: BaseScopedReadWriteLock(locker)
|
||||||
{
|
{
|
||||||
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
|
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
|
||||||
}
|
}
|
||||||
|
|
110
common/RwMutex.h
110
common/RwMutex.h
|
@ -19,72 +19,72 @@
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// RwMutex
|
// RwMutex
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class RwMutex
|
class RwMutex
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(RwMutex);
|
DeclareNoncopyableObject(RwMutex);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
pthread_rwlock_t m_rwlock;
|
pthread_rwlock_t m_rwlock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RwMutex();
|
RwMutex();
|
||||||
virtual ~RwMutex();
|
virtual ~RwMutex();
|
||||||
|
|
||||||
virtual void AcquireRead();
|
virtual void AcquireRead();
|
||||||
virtual void AcquireWrite();
|
virtual void AcquireWrite();
|
||||||
virtual bool TryAcquireRead();
|
virtual bool TryAcquireRead();
|
||||||
virtual bool TryAcquireWrite();
|
virtual bool TryAcquireWrite();
|
||||||
|
|
||||||
virtual void Release();
|
virtual void Release();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BaseScopedReadWriteLock
|
// BaseScopedReadWriteLock
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class BaseScopedReadWriteLock
|
class BaseScopedReadWriteLock
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(BaseScopedReadWriteLock);
|
DeclareNoncopyableObject(BaseScopedReadWriteLock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RwMutex &m_lock;
|
RwMutex& m_lock;
|
||||||
bool m_IsLocked;
|
bool m_IsLocked;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseScopedReadWriteLock(RwMutex &locker)
|
BaseScopedReadWriteLock(RwMutex& locker)
|
||||||
: m_lock(locker)
|
: m_lock(locker)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BaseScopedReadWriteLock();
|
virtual ~BaseScopedReadWriteLock();
|
||||||
|
|
||||||
void Release();
|
void Release();
|
||||||
bool IsLocked() const { return m_IsLocked; }
|
bool IsLocked() const { return m_IsLocked; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ScopedReadLock / ScopedWriteLock
|
// ScopedReadLock / ScopedWriteLock
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class ScopedReadLock : public BaseScopedReadWriteLock
|
class ScopedReadLock : public BaseScopedReadWriteLock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopedReadLock(RwMutex &locker);
|
ScopedReadLock(RwMutex& locker);
|
||||||
virtual ~ScopedReadLock() = default;
|
virtual ~ScopedReadLock() = default;
|
||||||
|
|
||||||
void Acquire();
|
void Acquire();
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScopedWriteLock : public BaseScopedReadWriteLock
|
class ScopedWriteLock : public BaseScopedReadWriteLock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopedWriteLock(RwMutex &locker);
|
ScopedWriteLock(RwMutex& locker);
|
||||||
virtual ~ScopedWriteLock() = default;
|
virtual ~ScopedWriteLock() = default;
|
||||||
|
|
||||||
void Acquire();
|
void Acquire();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ScopedWriteLock(RwMutex &locker, bool isTryLock);
|
ScopedWriteLock(RwMutex& locker, bool isTryLock);
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
// Microsoft Windows only macro, useful for freeing out COM objects:
|
// Microsoft Windows only macro, useful for freeing out COM objects:
|
||||||
#define safe_release(ptr) \
|
#define safe_release(ptr) \
|
||||||
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
|
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SafeArray
|
// SafeArray
|
||||||
|
@ -37,72 +37,72 @@
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class SafeArray
|
class SafeArray
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(SafeArray);
|
DeclareNoncopyableObject(SafeArray);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int DefaultChunkSize = 0x1000 * sizeof(T);
|
static const int DefaultChunkSize = 0x1000 * sizeof(T);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxString Name; // user-assigned block name
|
wxString Name; // user-assigned block name
|
||||||
int ChunkSize;
|
int ChunkSize;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T *m_ptr;
|
T* m_ptr;
|
||||||
int m_size; // size of the allocation of memory
|
int m_size; // size of the allocation of memory
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SafeArray(const wxChar *name, T *allocated_mem, int initSize);
|
SafeArray(const wxChar* name, T* allocated_mem, int initSize);
|
||||||
virtual T *_virtual_realloc(int newsize);
|
virtual T* _virtual_realloc(int newsize);
|
||||||
|
|
||||||
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
|
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
|
||||||
// builds only -- no bounds checking is done in release builds).
|
// builds only -- no bounds checking is done in release builds).
|
||||||
T *_getPtr(uint i) const;
|
T* _getPtr(uint i) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~SafeArray();
|
virtual ~SafeArray();
|
||||||
|
|
||||||
explicit SafeArray(const wxChar *name = L"Unnamed");
|
explicit SafeArray(const wxChar* name = L"Unnamed");
|
||||||
explicit SafeArray(int initialSize, const wxChar *name = L"Unnamed");
|
explicit SafeArray(int initialSize, const wxChar* name = L"Unnamed");
|
||||||
|
|
||||||
void Dispose();
|
void Dispose();
|
||||||
void ExactAlloc(int newsize);
|
void ExactAlloc(int newsize);
|
||||||
void MakeRoomFor(int newsize)
|
void MakeRoomFor(int newsize)
|
||||||
{
|
{
|
||||||
if (newsize > m_size)
|
if (newsize > m_size)
|
||||||
ExactAlloc(newsize);
|
ExactAlloc(newsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDisposed() const { return (m_ptr == NULL); }
|
bool IsDisposed() const { return (m_ptr == NULL); }
|
||||||
|
|
||||||
// Returns the size of the memory allocation, as according to the array type.
|
// Returns the size of the memory allocation, as according to the array type.
|
||||||
int GetLength() const { return m_size; }
|
int GetLength() const { return m_size; }
|
||||||
// Returns the size of the memory allocation in bytes.
|
// Returns the size of the memory allocation in bytes.
|
||||||
int GetSizeInBytes() const { return m_size * sizeof(T); }
|
int GetSizeInBytes() const { return m_size * sizeof(T); }
|
||||||
|
|
||||||
// Extends the containment area of the array. Extensions are performed
|
// Extends the containment area of the array. Extensions are performed
|
||||||
// in chunks.
|
// in chunks.
|
||||||
void GrowBy(int items)
|
void GrowBy(int items)
|
||||||
{
|
{
|
||||||
MakeRoomFor(m_size + ChunkSize + items + 1);
|
MakeRoomFor(m_size + ChunkSize + items + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a pointer to the requested allocation index.
|
// Gets a pointer to the requested allocation index.
|
||||||
// DevBuilds : Generates assertion if the index is invalid.
|
// DevBuilds : Generates assertion if the index is invalid.
|
||||||
T *GetPtr(uint idx = 0) { return _getPtr(idx); }
|
T* GetPtr(uint idx = 0) { return _getPtr(idx); }
|
||||||
const T *GetPtr(uint idx = 0) const { return _getPtr(idx); }
|
const T* GetPtr(uint idx = 0) const { return _getPtr(idx); }
|
||||||
|
|
||||||
// Gets a pointer to the element directly after the last element in the array.
|
// Gets a pointer to the element directly after the last element in the array.
|
||||||
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
|
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
|
||||||
// the out-of-bounds assertion check that typically occurs when you do that. :)
|
// the out-of-bounds assertion check that typically occurs when you do that. :)
|
||||||
T *GetPtrEnd() { return &m_ptr[m_size]; }
|
T* GetPtrEnd() { return &m_ptr[m_size]; }
|
||||||
const T *GetPtrEnd() const { return &m_ptr[m_size]; }
|
const T* GetPtrEnd() const { return &m_ptr[m_size]; }
|
||||||
|
|
||||||
// Gets an element of this memory allocation much as if it were an array.
|
// Gets an element of this memory allocation much as if it were an array.
|
||||||
// DevBuilds : Generates assertion if the index is invalid.
|
// DevBuilds : Generates assertion if the index is invalid.
|
||||||
T &operator[](int idx) { return *_getPtr((uint)idx); }
|
T& operator[](int idx) { return *_getPtr((uint)idx); }
|
||||||
const T &operator[](int idx) const { return *_getPtr((uint)idx); }
|
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||||
|
|
||||||
virtual SafeArray<T> *Clone() const;
|
virtual SafeArray<T>* Clone() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -118,73 +118,73 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class SafeList
|
class SafeList
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(SafeList);
|
DeclareNoncopyableObject(SafeList);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int DefaultChunkSize = 0x80 * sizeof(T);
|
static const int DefaultChunkSize = 0x80 * sizeof(T);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxString Name; // user-assigned block name
|
wxString Name; // user-assigned block name
|
||||||
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
|
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T *m_ptr;
|
T* m_ptr;
|
||||||
int m_allocsize; // size of the allocation of memory
|
int m_allocsize; // size of the allocation of memory
|
||||||
uint m_length; // length of the array (active items, not buffer allocation)
|
uint m_length; // length of the array (active items, not buffer allocation)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual T *_virtual_realloc(int newsize);
|
virtual T* _virtual_realloc(int newsize);
|
||||||
void _MakeRoomFor_threshold(int newsize);
|
void _MakeRoomFor_threshold(int newsize);
|
||||||
|
|
||||||
T *_getPtr(uint i) const;
|
T* _getPtr(uint i) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~SafeList();
|
virtual ~SafeList();
|
||||||
explicit SafeList(const wxChar *name = L"Unnamed");
|
explicit SafeList(const wxChar* name = L"Unnamed");
|
||||||
explicit SafeList(int initialSize, const wxChar *name = L"Unnamed");
|
explicit SafeList(int initialSize, const wxChar* name = L"Unnamed");
|
||||||
virtual SafeList<T> *Clone() const;
|
virtual SafeList<T>* Clone() const;
|
||||||
|
|
||||||
void Remove(int index);
|
void Remove(int index);
|
||||||
void MakeRoomFor(int blockSize);
|
void MakeRoomFor(int blockSize);
|
||||||
|
|
||||||
T &New();
|
T& New();
|
||||||
int Add(const T &src);
|
int Add(const T& src);
|
||||||
T &AddNew(const T &src);
|
T& AddNew(const T& src);
|
||||||
|
|
||||||
// Returns the size of the list, as according to the array type. This includes
|
// Returns the size of the list, as according to the array type. This includes
|
||||||
// mapped items only. The actual size of the allocation may differ.
|
// mapped items only. The actual size of the allocation may differ.
|
||||||
int GetLength() const { return m_length; }
|
int GetLength() const { return m_length; }
|
||||||
|
|
||||||
// Returns the size of the list, in bytes. This includes mapped items only.
|
// Returns the size of the list, in bytes. This includes mapped items only.
|
||||||
// The actual size of the allocation may differ.
|
// The actual size of the allocation may differ.
|
||||||
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
||||||
|
|
||||||
void MatchLengthToAllocatedSize()
|
void MatchLengthToAllocatedSize()
|
||||||
{
|
{
|
||||||
m_length = m_allocsize;
|
m_length = m_allocsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrowBy(int items)
|
void GrowBy(int items)
|
||||||
{
|
{
|
||||||
MakeRoomFor(m_length + ChunkSize + items + 1);
|
MakeRoomFor(m_length + ChunkSize + items + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the item length to zero. Does not free memory allocations.
|
// Sets the item length to zero. Does not free memory allocations.
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
m_length = 0;
|
m_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets an element of this memory allocation much as if it were an array.
|
// Gets an element of this memory allocation much as if it were an array.
|
||||||
// DevBuilds : Generates assertion if the index is invalid.
|
// DevBuilds : Generates assertion if the index is invalid.
|
||||||
T &operator[](int idx) { return *_getPtr((uint)idx); }
|
T& operator[](int idx) { return *_getPtr((uint)idx); }
|
||||||
const T &operator[](int idx) const { return *_getPtr((uint)idx); }
|
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||||
|
|
||||||
T *GetPtr() { return m_ptr; }
|
T* GetPtr() { return m_ptr; }
|
||||||
const T *GetPtr() const { return m_ptr; }
|
const T* GetPtr() const { return m_ptr; }
|
||||||
|
|
||||||
T &GetLast() { return m_ptr[m_length - 1]; }
|
T& GetLast() { return m_ptr[m_length - 1]; }
|
||||||
const T &GetLast() const { return m_ptr[m_length - 1]; }
|
const T& GetLast() const { return m_ptr[m_length - 1]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -197,21 +197,21 @@ public:
|
||||||
template <typename T, uint Alignment>
|
template <typename T, uint Alignment>
|
||||||
class SafeAlignedArray : public SafeArray<T>
|
class SafeAlignedArray : public SafeArray<T>
|
||||||
{
|
{
|
||||||
typedef SafeArray<T> _parent;
|
typedef SafeArray<T> _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T *_virtual_realloc(int newsize);
|
T* _virtual_realloc(int newsize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using _parent::operator[];
|
using _parent::operator[];
|
||||||
|
|
||||||
virtual ~SafeAlignedArray();
|
virtual ~SafeAlignedArray();
|
||||||
|
|
||||||
explicit SafeAlignedArray(const wxChar *name = L"Unnamed")
|
explicit SafeAlignedArray(const wxChar* name = L"Unnamed")
|
||||||
: SafeArray<T>::SafeArray(name)
|
: SafeArray<T>::SafeArray(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit SafeAlignedArray(int initialSize, const wxChar *name = L"Unnamed");
|
explicit SafeAlignedArray(int initialSize, const wxChar* name = L"Unnamed");
|
||||||
virtual SafeAlignedArray<T, Alignment> *Clone() const;
|
virtual SafeAlignedArray<T, Alignment>* Clone() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,79 +23,80 @@
|
||||||
// Throws:
|
// Throws:
|
||||||
// Exception::OutOfMemory if the allocated_mem pointer is NULL.
|
// Exception::OutOfMemory if the allocated_mem pointer is NULL.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeArray<T>::SafeArray(const wxChar *name, T *allocated_mem, int initSize)
|
SafeArray<T>::SafeArray(const wxChar* name, T* allocated_mem, int initSize)
|
||||||
: Name(name)
|
: Name(name)
|
||||||
{
|
{
|
||||||
ChunkSize = DefaultChunkSize;
|
ChunkSize = DefaultChunkSize;
|
||||||
m_ptr = allocated_mem;
|
m_ptr = allocated_mem;
|
||||||
m_size = initSize;
|
m_size = initSize;
|
||||||
|
|
||||||
if (m_ptr == NULL)
|
if (m_ptr == NULL)
|
||||||
throw Exception::OutOfMemory(name)
|
throw Exception::OutOfMemory(name)
|
||||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
|
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *SafeArray<T>::_virtual_realloc(int newsize)
|
T* SafeArray<T>::_virtual_realloc(int newsize)
|
||||||
{
|
{
|
||||||
T *retval = (T *)((m_ptr == NULL) ?
|
T* retval = (T*)((m_ptr == NULL) ?
|
||||||
malloc(newsize * sizeof(T)) :
|
malloc(newsize * sizeof(T)) :
|
||||||
realloc(m_ptr, newsize * sizeof(T)));
|
realloc(m_ptr, newsize * sizeof(T)));
|
||||||
|
|
||||||
if (IsDebugBuild && (retval != NULL)) {
|
if (IsDebugBuild && (retval != NULL))
|
||||||
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
{
|
||||||
// to a debuggee
|
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
||||||
|
// to a debuggee
|
||||||
|
|
||||||
u32 *fill = (u32 *)&retval[m_size];
|
u32* fill = (u32*)&retval[m_size];
|
||||||
const u32 *end = (u32 *)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
|
const u32* end = (u32*)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
|
||||||
for (; fill < end; ++fill)
|
for (; fill < end; ++fill)
|
||||||
*fill = 0xbaadf00d;
|
*fill = 0xbaadf00d;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeArray<T>::~SafeArray()
|
SafeArray<T>::~SafeArray()
|
||||||
{
|
{
|
||||||
safe_free(m_ptr);
|
safe_free(m_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeArray<T>::SafeArray(const wxChar *name)
|
SafeArray<T>::SafeArray(const wxChar* name)
|
||||||
: Name(name)
|
: Name(name)
|
||||||
{
|
{
|
||||||
ChunkSize = DefaultChunkSize;
|
ChunkSize = DefaultChunkSize;
|
||||||
m_ptr = NULL;
|
m_ptr = NULL;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeArray<T>::SafeArray(int initialSize, const wxChar *name)
|
SafeArray<T>::SafeArray(int initialSize, const wxChar* name)
|
||||||
: Name(name)
|
: Name(name)
|
||||||
{
|
{
|
||||||
ChunkSize = DefaultChunkSize;
|
ChunkSize = DefaultChunkSize;
|
||||||
m_ptr = (initialSize == 0) ? NULL : (T *)malloc(initialSize * sizeof(T));
|
m_ptr = (initialSize == 0) ? NULL : (T*)malloc(initialSize * sizeof(T));
|
||||||
m_size = initialSize;
|
m_size = initialSize;
|
||||||
|
|
||||||
if ((initialSize != 0) && (m_ptr == NULL))
|
if ((initialSize != 0) && (m_ptr == NULL))
|
||||||
throw Exception::OutOfMemory(name)
|
throw Exception::OutOfMemory(name)
|
||||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
|
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the contents of the array to zero, and frees all memory allocations.
|
// Clears the contents of the array to zero, and frees all memory allocations.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeArray<T>::Dispose()
|
void SafeArray<T>::Dispose()
|
||||||
{
|
{
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
safe_free(m_ptr);
|
safe_free(m_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *SafeArray<T>::_getPtr(uint i) const
|
T* SafeArray<T>::_getPtr(uint i) const
|
||||||
{
|
{
|
||||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_size);
|
IndexBoundsAssumeDev(WX_STR(Name), i, m_size);
|
||||||
return &m_ptr[i];
|
return &m_ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// reallocates the array to the explicit size. Can be used to shrink or grow an
|
// reallocates the array to the explicit size. Can be used to shrink or grow an
|
||||||
|
@ -103,23 +104,23 @@ T *SafeArray<T>::_getPtr(uint i) const
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeArray<T>::ExactAlloc(int newsize)
|
void SafeArray<T>::ExactAlloc(int newsize)
|
||||||
{
|
{
|
||||||
if (newsize == m_size)
|
if (newsize == m_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_ptr = _virtual_realloc(newsize);
|
m_ptr = _virtual_realloc(newsize);
|
||||||
if (m_ptr == NULL)
|
if (m_ptr == NULL)
|
||||||
throw Exception::OutOfMemory(Name)
|
throw Exception::OutOfMemory(Name)
|
||||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
|
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
|
||||||
|
|
||||||
m_size = newsize;
|
m_size = newsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeArray<T> *SafeArray<T>::Clone() const
|
SafeArray<T>* SafeArray<T>::Clone() const
|
||||||
{
|
{
|
||||||
SafeArray<T> *retval = new SafeArray<T>(m_size);
|
SafeArray<T>* retval = new SafeArray<T>(m_size);
|
||||||
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
|
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,11 +129,11 @@ SafeArray<T> *SafeArray<T>::Clone() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <typename T, uint Alignment>
|
template <typename T, uint Alignment>
|
||||||
T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
T* SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
||||||
{
|
{
|
||||||
return (T *)((this->m_ptr == NULL) ?
|
return (T*)((this->m_ptr == NULL) ?
|
||||||
_aligned_malloc(newsize * sizeof(T), Alignment) :
|
_aligned_malloc(newsize * sizeof(T), Alignment) :
|
||||||
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
|
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends "(align: xx)" to the name of the allocation in devel builds.
|
// Appends "(align: xx)" to the name of the allocation in devel builds.
|
||||||
|
@ -141,25 +142,25 @@ T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
||||||
template <typename T, uint Alignment>
|
template <typename T, uint Alignment>
|
||||||
SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
|
SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
|
||||||
{
|
{
|
||||||
safe_aligned_free(this->m_ptr);
|
safe_aligned_free(this->m_ptr);
|
||||||
// mptr is set to null, so the parent class's destructor won't re-free it.
|
// mptr is set to null, so the parent class's destructor won't re-free it.
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, uint Alignment>
|
template <typename T, uint Alignment>
|
||||||
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar *name)
|
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar* name)
|
||||||
: SafeArray<T>::SafeArray(
|
: SafeArray<T>::SafeArray(
|
||||||
name,
|
name,
|
||||||
(T *)_aligned_malloc(initialSize * sizeof(T), Alignment),
|
(T*)_aligned_malloc(initialSize * sizeof(T), Alignment),
|
||||||
initialSize)
|
initialSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, uint Alignment>
|
template <typename T, uint Alignment>
|
||||||
SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const
|
SafeAlignedArray<T, Alignment>* SafeAlignedArray<T, Alignment>::Clone() const
|
||||||
{
|
{
|
||||||
SafeAlignedArray<T, Alignment> *retval = new SafeAlignedArray<T, Alignment>(this->m_size);
|
SafeAlignedArray<T, Alignment>* retval = new SafeAlignedArray<T, Alignment>(this->m_size);
|
||||||
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
|
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -167,50 +168,51 @@ SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *SafeList<T>::_virtual_realloc(int newsize)
|
T* SafeList<T>::_virtual_realloc(int newsize)
|
||||||
{
|
{
|
||||||
return (T *)realloc(m_ptr, newsize * sizeof(T));
|
return (T*)realloc(m_ptr, newsize * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeList<T>::~SafeList()
|
SafeList<T>::~SafeList()
|
||||||
{
|
{
|
||||||
safe_free(m_ptr);
|
safe_free(m_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeList<T>::SafeList(const wxChar *name)
|
SafeList<T>::SafeList(const wxChar* name)
|
||||||
: Name(name)
|
: Name(name)
|
||||||
{
|
{
|
||||||
ChunkSize = DefaultChunkSize;
|
ChunkSize = DefaultChunkSize;
|
||||||
m_ptr = NULL;
|
m_ptr = NULL;
|
||||||
m_allocsize = 0;
|
m_allocsize = 0;
|
||||||
m_length = 0;
|
m_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeList<T>::SafeList(int initialSize, const wxChar *name)
|
SafeList<T>::SafeList(int initialSize, const wxChar* name)
|
||||||
: Name(name)
|
: Name(name)
|
||||||
{
|
{
|
||||||
ChunkSize = DefaultChunkSize;
|
ChunkSize = DefaultChunkSize;
|
||||||
m_allocsize = initialSize;
|
m_allocsize = initialSize;
|
||||||
m_length = 0;
|
m_length = 0;
|
||||||
m_ptr = (T *)malloc(initialSize * sizeof(T));
|
m_ptr = (T*)malloc(initialSize * sizeof(T));
|
||||||
|
|
||||||
if (m_ptr == NULL)
|
if (m_ptr == NULL)
|
||||||
throw Exception::OutOfMemory(Name)
|
throw Exception::OutOfMemory(Name)
|
||||||
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
||||||
|
|
||||||
for (int i = 0; i < m_allocsize; ++i) {
|
for (int i = 0; i < m_allocsize; ++i)
|
||||||
new (&m_ptr[i]) T();
|
{
|
||||||
}
|
new (&m_ptr[i]) T();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *SafeList<T>::_getPtr(uint i) const
|
T* SafeList<T>::_getPtr(uint i) const
|
||||||
{
|
{
|
||||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_length);
|
IndexBoundsAssumeDev(WX_STR(Name), i, m_length);
|
||||||
return &m_ptr[i];
|
return &m_ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures that the allocation is large enough to fit data of the
|
// Ensures that the allocation is large enough to fit data of the
|
||||||
|
@ -218,42 +220,44 @@ T *SafeList<T>::_getPtr(uint i) const
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeList<T>::MakeRoomFor(int blockSize)
|
void SafeList<T>::MakeRoomFor(int blockSize)
|
||||||
{
|
{
|
||||||
if (blockSize > m_allocsize) {
|
if (blockSize > m_allocsize)
|
||||||
const int newalloc = blockSize + ChunkSize;
|
{
|
||||||
m_ptr = _virtual_realloc(newalloc);
|
const int newalloc = blockSize + ChunkSize;
|
||||||
if (m_ptr == NULL)
|
m_ptr = _virtual_realloc(newalloc);
|
||||||
throw Exception::OutOfMemory(Name)
|
if (m_ptr == NULL)
|
||||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
throw Exception::OutOfMemory(Name)
|
||||||
|
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
||||||
|
|
||||||
for (; m_allocsize < newalloc; ++m_allocsize) {
|
for (; m_allocsize < newalloc; ++m_allocsize)
|
||||||
new (&m_ptr[m_allocsize]) T();
|
{
|
||||||
}
|
new (&m_ptr[m_allocsize]) T();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends an item to the end of the list and returns a handle to it.
|
// Appends an item to the end of the list and returns a handle to it.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T &SafeList<T>::New()
|
T& SafeList<T>::New()
|
||||||
{
|
{
|
||||||
_MakeRoomFor_threshold(m_length + 1);
|
_MakeRoomFor_threshold(m_length + 1);
|
||||||
return m_ptr[m_length++];
|
return m_ptr[m_length++];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int SafeList<T>::Add(const T &src)
|
int SafeList<T>::Add(const T& src)
|
||||||
{
|
{
|
||||||
_MakeRoomFor_threshold(m_length + 1);
|
_MakeRoomFor_threshold(m_length + 1);
|
||||||
m_ptr[m_length] = src;
|
m_ptr[m_length] = src;
|
||||||
return m_length++;
|
return m_length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as Add, but returns the handle of the new object instead of it's array index.
|
// Same as Add, but returns the handle of the new object instead of it's array index.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T &SafeList<T>::AddNew(const T &src)
|
T& SafeList<T>::AddNew(const T& src)
|
||||||
{
|
{
|
||||||
_MakeRoomFor_threshold(m_length + 1);
|
_MakeRoomFor_threshold(m_length + 1);
|
||||||
m_ptr[m_length] = src;
|
m_ptr[m_length] = src;
|
||||||
return m_ptr[m_length];
|
return m_ptr[m_length];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs a standard array-copy removal of the given item. All items past the
|
// Performs a standard array-copy removal of the given item. All items past the
|
||||||
|
@ -262,23 +266,23 @@ T &SafeList<T>::AddNew(const T &src)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeList<T>::Remove(int index)
|
void SafeList<T>::Remove(int index)
|
||||||
{
|
{
|
||||||
IndexBoundsAssumeDev(Name.c_str(), index, m_length);
|
IndexBoundsAssumeDev(Name.c_str(), index, m_length);
|
||||||
|
|
||||||
int copylen = m_length - index;
|
int copylen = m_length - index;
|
||||||
if (copylen > 0)
|
if (copylen > 0)
|
||||||
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
|
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SafeList<T> *SafeList<T>::Clone() const
|
SafeList<T>* SafeList<T>::Clone() const
|
||||||
{
|
{
|
||||||
SafeList<T> *retval = new SafeList<T>(m_length);
|
SafeList<T>* retval = new SafeList<T>(m_length);
|
||||||
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
|
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeList<T>::_MakeRoomFor_threshold(int newsize)
|
void SafeList<T>::_MakeRoomFor_threshold(int newsize)
|
||||||
{
|
{
|
||||||
MakeRoomFor(newsize + ChunkSize);
|
MakeRoomFor(newsize + ChunkSize);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,34 +28,34 @@
|
||||||
// pointer to null after deallocation.
|
// pointer to null after deallocation.
|
||||||
|
|
||||||
#define safe_delete(ptr) \
|
#define safe_delete(ptr) \
|
||||||
((void)(delete (ptr)), (ptr) = NULL)
|
((void)(delete (ptr)), (ptr) = NULL)
|
||||||
|
|
||||||
#define safe_delete_array(ptr) \
|
#define safe_delete_array(ptr) \
|
||||||
((void)(delete[](ptr)), (ptr) = NULL)
|
((void)(delete[](ptr)), (ptr) = NULL)
|
||||||
|
|
||||||
// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on
|
// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on
|
||||||
// just about every compiler and libc implementation of any recentness.
|
// just about every compiler and libc implementation of any recentness.
|
||||||
#define safe_free(ptr) \
|
#define safe_free(ptr) \
|
||||||
((void)(free(ptr), !!0), (ptr) = NULL)
|
((void)(free(ptr), !!0), (ptr) = NULL)
|
||||||
//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
|
//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
|
||||||
|
|
||||||
#define safe_fclose(ptr) \
|
#define safe_fclose(ptr) \
|
||||||
((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL))
|
((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL))
|
||||||
|
|
||||||
// Implementation note: all known implementations of _aligned_free check the pointer for
|
// Implementation note: all known implementations of _aligned_free check the pointer for
|
||||||
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
|
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
|
||||||
// do it here.
|
// do it here.
|
||||||
#define safe_aligned_free(ptr) \
|
#define safe_aligned_free(ptr) \
|
||||||
((void)(_aligned_free(ptr), (ptr) = NULL))
|
((void)(_aligned_free(ptr), (ptr) = NULL))
|
||||||
|
|
||||||
// aligned_malloc: Implement/declare linux equivalents here!
|
// aligned_malloc: Implement/declare linux equivalents here!
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
extern void *__fastcall _aligned_malloc(size_t size, size_t align);
|
extern void* __fastcall _aligned_malloc(size_t size, size_t align);
|
||||||
extern void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size);
|
extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size);
|
||||||
extern void _aligned_free(void *pmem);
|
extern void _aligned_free(void* pmem);
|
||||||
#else
|
#else
|
||||||
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
|
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
|
||||||
_aligned_realloc(handle, new_size, align)
|
_aligned_realloc(handle, new_size, align)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -63,7 +63,7 @@ extern void _aligned_free(void *pmem);
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
typedef void FnType_OutOfMemory(uptr blocksize);
|
typedef void FnType_OutOfMemory(uptr blocksize);
|
||||||
typedef FnType_OutOfMemory *Fnptr_OutOfMemory;
|
typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
|
||||||
|
|
||||||
// This method is meant to be assigned by applications that link against pxWex. It is called
|
// This method is meant to be assigned by applications that link against pxWex. It is called
|
||||||
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
|
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
|
||||||
|
@ -93,74 +93,74 @@ template <typename T>
|
||||||
class BaseScopedAlloc
|
class BaseScopedAlloc
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
T *m_buffer;
|
T* m_buffer;
|
||||||
uint m_size;
|
uint m_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseScopedAlloc()
|
BaseScopedAlloc()
|
||||||
{
|
{
|
||||||
m_buffer = NULL;
|
m_buffer = NULL;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BaseScopedAlloc()
|
virtual ~BaseScopedAlloc()
|
||||||
{
|
{
|
||||||
//pxAssert(m_buffer==NULL);
|
//pxAssert(m_buffer==NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
size_t GetSize() const { return m_size; }
|
size_t GetSize() const { return m_size; }
|
||||||
size_t GetLength() const { return m_size; }
|
size_t GetLength() const { return m_size; }
|
||||||
|
|
||||||
// Allocates the object to the specified size. If an existing allocation is in
|
// Allocates the object to the specified size. If an existing allocation is in
|
||||||
// place, it is freed and replaced with the new allocation, and all data is lost.
|
// place, it is freed and replaced with the new allocation, and all data is lost.
|
||||||
// Parameter:
|
// Parameter:
|
||||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||||
// size is 0, the the allocation is freed, same as calling Free().
|
// size is 0, the the allocation is freed, same as calling Free().
|
||||||
virtual void Alloc(size_t newsize) = 0;
|
virtual void Alloc(size_t newsize) = 0;
|
||||||
|
|
||||||
// Re-sizes the allocation to the requested size, without any data loss.
|
// Re-sizes the allocation to the requested size, without any data loss.
|
||||||
// Parameter:
|
// Parameter:
|
||||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||||
// size is 0, the the allocation is freed, same as calling Free().
|
// size is 0, the the allocation is freed, same as calling Free().
|
||||||
virtual void Resize(size_t newsize) = 0;
|
virtual void Resize(size_t newsize) = 0;
|
||||||
|
|
||||||
void Free()
|
void Free()
|
||||||
{
|
{
|
||||||
Alloc(0);
|
Alloc(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Makes enough room for the requested size. Existing data in the array is retained.
|
// Makes enough room for the requested size. Existing data in the array is retained.
|
||||||
void MakeRoomFor(uint size)
|
void MakeRoomFor(uint size)
|
||||||
{
|
{
|
||||||
if (size <= m_size)
|
if (size <= m_size)
|
||||||
return;
|
return;
|
||||||
Resize(size);
|
Resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
T *GetPtr(uint idx = 0) const
|
T* GetPtr(uint idx = 0) const
|
||||||
{
|
{
|
||||||
#if pxUSE_SECURE_MALLOC
|
#if pxUSE_SECURE_MALLOC
|
||||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||||
#endif
|
#endif
|
||||||
return &m_buffer[idx];
|
return &m_buffer[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
T &operator[](uint idx)
|
T& operator[](uint idx)
|
||||||
{
|
{
|
||||||
#if pxUSE_SECURE_MALLOC
|
#if pxUSE_SECURE_MALLOC
|
||||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||||
#endif
|
#endif
|
||||||
return m_buffer[idx];
|
return m_buffer[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &operator[](uint idx) const
|
const T& operator[](uint idx) const
|
||||||
{
|
{
|
||||||
#if pxUSE_SECURE_MALLOC
|
#if pxUSE_SECURE_MALLOC
|
||||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||||
#endif
|
#endif
|
||||||
return m_buffer[idx];
|
return m_buffer[idx];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -175,42 +175,42 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ScopedAlloc : public BaseScopedAlloc<T>
|
class ScopedAlloc : public BaseScopedAlloc<T>
|
||||||
{
|
{
|
||||||
typedef BaseScopedAlloc<T> _parent;
|
typedef BaseScopedAlloc<T> _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedAlloc(size_t size = 0)
|
ScopedAlloc(size_t size = 0)
|
||||||
: _parent()
|
: _parent()
|
||||||
{
|
{
|
||||||
Alloc(size);
|
Alloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ScopedAlloc()
|
virtual ~ScopedAlloc()
|
||||||
{
|
{
|
||||||
safe_free(this->m_buffer);
|
safe_free(this->m_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Alloc(size_t newsize)
|
virtual void Alloc(size_t newsize)
|
||||||
{
|
{
|
||||||
safe_free(this->m_buffer);
|
safe_free(this->m_buffer);
|
||||||
this->m_size = newsize;
|
this->m_size = newsize;
|
||||||
if (!this->m_size)
|
if (!this->m_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_buffer = (T *)malloc(this->m_size * sizeof(T));
|
this->m_buffer = (T*)malloc(this->m_size * sizeof(T));
|
||||||
if (!this->m_buffer)
|
if (!this->m_buffer)
|
||||||
throw Exception::OutOfMemory(L"ScopedAlloc");
|
throw Exception::OutOfMemory(L"ScopedAlloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Resize(size_t newsize)
|
virtual void Resize(size_t newsize)
|
||||||
{
|
{
|
||||||
this->m_size = newsize;
|
this->m_size = newsize;
|
||||||
this->m_buffer = (T *)realloc(this->m_buffer, this->m_size * sizeof(T));
|
this->m_buffer = (T*)realloc(this->m_buffer, this->m_size * sizeof(T));
|
||||||
|
|
||||||
if (!this->m_buffer)
|
if (!this->m_buffer)
|
||||||
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
|
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
|
||||||
}
|
}
|
||||||
|
|
||||||
using _parent::operator[];
|
using _parent::operator[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -225,40 +225,40 @@ public:
|
||||||
template <typename T, uint align>
|
template <typename T, uint align>
|
||||||
class ScopedAlignedAlloc : public BaseScopedAlloc<T>
|
class ScopedAlignedAlloc : public BaseScopedAlloc<T>
|
||||||
{
|
{
|
||||||
typedef BaseScopedAlloc<T> _parent;
|
typedef BaseScopedAlloc<T> _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedAlignedAlloc(size_t size = 0)
|
ScopedAlignedAlloc(size_t size = 0)
|
||||||
: _parent()
|
: _parent()
|
||||||
{
|
{
|
||||||
Alloc(size);
|
Alloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ScopedAlignedAlloc()
|
virtual ~ScopedAlignedAlloc()
|
||||||
{
|
{
|
||||||
safe_aligned_free(this->m_buffer);
|
safe_aligned_free(this->m_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Alloc(size_t newsize)
|
virtual void Alloc(size_t newsize)
|
||||||
{
|
{
|
||||||
safe_aligned_free(this->m_buffer);
|
safe_aligned_free(this->m_buffer);
|
||||||
this->m_size = newsize;
|
this->m_size = newsize;
|
||||||
if (!this->m_size)
|
if (!this->m_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_buffer = (T *)_aligned_malloc(this->m_size * sizeof(T), align);
|
this->m_buffer = (T*)_aligned_malloc(this->m_size * sizeof(T), align);
|
||||||
if (!this->m_buffer)
|
if (!this->m_buffer)
|
||||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
|
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Resize(size_t newsize)
|
virtual void Resize(size_t newsize)
|
||||||
{
|
{
|
||||||
this->m_buffer = (T *)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T));
|
this->m_buffer = (T*)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T));
|
||||||
this->m_size = newsize;
|
this->m_size = newsize;
|
||||||
|
|
||||||
if (!this->m_buffer)
|
if (!this->m_buffer)
|
||||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
|
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
|
||||||
}
|
}
|
||||||
|
|
||||||
using _parent::operator[];
|
using _parent::operator[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,91 +25,91 @@ using Threading::ScopedLock;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ScopedPtrMT
|
class ScopedPtrMT
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ScopedPtrMT);
|
DeclareNoncopyableObject(ScopedPtrMT);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::atomic<T *> m_ptr;
|
std::atomic<T*> m_ptr;
|
||||||
Threading::Mutex m_mtx;
|
Threading::Mutex m_mtx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
|
|
||||||
wxEXPLICIT ScopedPtrMT(T *ptr = nullptr)
|
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
|
||||||
{
|
{
|
||||||
m_ptr = ptr;
|
m_ptr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScopedPtrMT() { _Delete_unlocked(); }
|
~ScopedPtrMT() { _Delete_unlocked(); }
|
||||||
|
|
||||||
ScopedPtrMT &Reassign(T *ptr = nullptr)
|
ScopedPtrMT& Reassign(T* ptr = nullptr)
|
||||||
{
|
{
|
||||||
T *doh = m_ptr.exchange(ptr);
|
T* doh = m_ptr.exchange(ptr);
|
||||||
if (ptr != doh)
|
if (ptr != doh)
|
||||||
delete doh;
|
delete doh;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedPtrMT &Delete() noexcept
|
ScopedPtrMT& Delete() noexcept
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_mtx);
|
ScopedLock lock(m_mtx);
|
||||||
_Delete_unlocked();
|
_Delete_unlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the pointer from scoped management, but does not delete!
|
// Removes the pointer from scoped management, but does not delete!
|
||||||
// (ScopedPtr will be nullptr after this method)
|
// (ScopedPtr will be nullptr after this method)
|
||||||
T *DetachPtr()
|
T* DetachPtr()
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_mtx);
|
ScopedLock lock(m_mtx);
|
||||||
|
|
||||||
return m_ptr.exchange(nullptr);
|
return m_ptr.exchange(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
|
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
|
||||||
// has no object in management.
|
// has no object in management.
|
||||||
T *GetPtr() const
|
T* GetPtr() const
|
||||||
{
|
{
|
||||||
return m_ptr;
|
return m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapPtr(ScopedPtrMT &other)
|
void SwapPtr(ScopedPtrMT& other)
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_mtx);
|
ScopedLock lock(m_mtx);
|
||||||
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
|
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
|
||||||
T *const tmp = other.m_ptr;
|
T* const tmp = other.m_ptr;
|
||||||
other.m_ptr = m_ptr;
|
other.m_ptr = m_ptr;
|
||||||
m_ptr = tmp;
|
m_ptr = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// ScopedPtrMT Operators
|
// ScopedPtrMT Operators
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
||||||
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
||||||
// allow the T* implicit casting.
|
// allow the T* implicit casting.
|
||||||
|
|
||||||
bool operator!() const noexcept
|
bool operator!() const noexcept
|
||||||
{
|
{
|
||||||
return m_ptr.load() == nullptr;
|
return m_ptr.load() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equality
|
// Equality
|
||||||
bool operator==(T *pT) const noexcept
|
bool operator==(T* pT) const noexcept
|
||||||
{
|
{
|
||||||
return m_ptr == pT;
|
return m_ptr == pT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inequality
|
// Inequality
|
||||||
bool operator!=(T *pT) const noexcept
|
bool operator!=(T* pT) const noexcept
|
||||||
{
|
{
|
||||||
return !operator==(pT);
|
return !operator==(pT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
|
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
|
||||||
// of the managed pointer.
|
// of the managed pointer.
|
||||||
ScopedPtrMT &operator=(T *src)
|
ScopedPtrMT& operator=(T* src)
|
||||||
{
|
{
|
||||||
return Reassign(src);
|
return Reassign(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
operator T*() const
|
operator T*() const
|
||||||
|
@ -133,8 +133,8 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _Delete_unlocked() noexcept
|
void _Delete_unlocked() noexcept
|
||||||
{
|
{
|
||||||
delete m_ptr.exchange(nullptr);
|
delete m_ptr.exchange(nullptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,49 +26,50 @@
|
||||||
|
|
||||||
Threading::Semaphore::Semaphore()
|
Threading::Semaphore::Semaphore()
|
||||||
{
|
{
|
||||||
sem_init(&m_sema, false, 0);
|
sem_init(&m_sema, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Threading::Semaphore::~Semaphore()
|
Threading::Semaphore::~Semaphore()
|
||||||
{
|
{
|
||||||
sem_destroy(&m_sema);
|
sem_destroy(&m_sema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Reset()
|
void Threading::Semaphore::Reset()
|
||||||
{
|
{
|
||||||
sem_destroy(&m_sema);
|
sem_destroy(&m_sema);
|
||||||
sem_init(&m_sema, false, 0);
|
sem_init(&m_sema, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Post()
|
void Threading::Semaphore::Post()
|
||||||
{
|
{
|
||||||
sem_post(&m_sema);
|
sem_post(&m_sema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::Post(int multiple)
|
void Threading::Semaphore::Post(int multiple)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
sem_post_multiple(&m_sema, multiple);
|
sem_post_multiple(&m_sema, multiple);
|
||||||
#else
|
#else
|
||||||
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
||||||
while (multiple > 0) {
|
while (multiple > 0)
|
||||||
multiple--;
|
{
|
||||||
sem_post(&m_sema);
|
multiple--;
|
||||||
}
|
sem_post(&m_sema);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::WaitWithoutYield()
|
void Threading::Semaphore::WaitWithoutYield()
|
||||||
{
|
{
|
||||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||||
sem_wait(&m_sema);
|
sem_wait(&m_sema);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||||
return sem_timedwait(&m_sema, &fail) == 0;
|
return sem_timedwait(&m_sema, &fail) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,18 +81,23 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
void Threading::Semaphore::Wait()
|
void Threading::Semaphore::Wait()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
sem_wait(&m_sema);
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
sem_wait(&m_sema);
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
sem_wait(&m_sema);
|
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||||
} else {
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
while (!WaitWithoutYield(def_yieldgui_interval))
|
sem_wait(&m_sema);
|
||||||
YieldToMain();
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
|
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||||
|
YieldToMain();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
sem_wait(&m_sema);
|
sem_wait(&m_sema);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,29 +110,35 @@ void Threading::Semaphore::Wait()
|
||||||
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
||||||
// reached prior to timeout.
|
// reached prior to timeout.
|
||||||
//
|
//
|
||||||
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
return WaitWithoutYield(timeout);
|
{
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
return WaitWithoutYield(timeout);
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
}
|
||||||
return WaitWithoutYield(timeout);
|
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||||
} else {
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
wxTimeSpan countdown((timeout));
|
return WaitWithoutYield(timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
if (WaitWithoutYield(def_yieldgui_interval))
|
{
|
||||||
break;
|
if (WaitWithoutYield(def_yieldgui_interval))
|
||||||
YieldToMain();
|
break;
|
||||||
countdown -= def_yieldgui_interval;
|
YieldToMain();
|
||||||
} while (countdown.GetMilliseconds() > 0);
|
countdown -= def_yieldgui_interval;
|
||||||
|
} while (countdown.GetMilliseconds() > 0);
|
||||||
|
|
||||||
return countdown.GetMilliseconds() > 0;
|
return countdown.GetMilliseconds() > 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,26 +152,26 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
||||||
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
|
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
|
||||||
void Threading::Semaphore::WaitNoCancel()
|
void Threading::Semaphore::WaitNoCancel()
|
||||||
{
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||||
//WaitWithoutYield();
|
//WaitWithoutYield();
|
||||||
Wait();
|
Wait();
|
||||||
pthread_setcancelstate(oldstate, NULL);
|
pthread_setcancelstate(oldstate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout)
|
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||||
//WaitWithoutYield( timeout );
|
//WaitWithoutYield( timeout );
|
||||||
Wait(timeout);
|
Wait(timeout);
|
||||||
pthread_setcancelstate(oldstate, NULL);
|
pthread_setcancelstate(oldstate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Threading::Semaphore::Count()
|
int Threading::Semaphore::Count()
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
sem_getvalue(&m_sema, &retval);
|
sem_getvalue(&m_sema, &retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,59 +17,59 @@
|
||||||
#include "common/Pcsx2Defs.h"
|
#include "common/Pcsx2Defs.h"
|
||||||
#include "common/StringHelpers.h"
|
#include "common/StringHelpers.h"
|
||||||
|
|
||||||
__fi wxString fromUTF8(const char *src)
|
__fi wxString fromUTF8(const char* src)
|
||||||
{
|
{
|
||||||
// IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of
|
// IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of
|
||||||
// wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or
|
// wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or
|
||||||
// destructor that attempts to do logging may crash the app (either during startup or during exit) unless
|
// destructor that attempts to do logging may crash the app (either during startup or during exit) unless
|
||||||
// we use a LOCAL instance of wxMBConvUTF8(). --air
|
// we use a LOCAL instance of wxMBConvUTF8(). --air
|
||||||
|
|
||||||
// Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class
|
// Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class
|
||||||
// is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets
|
// is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets
|
||||||
// uses the stupid globals in the first place!) --air
|
// uses the stupid globals in the first place!) --air
|
||||||
|
|
||||||
return wxString(src, wxMBConvUTF8());
|
return wxString(src, wxMBConvUTF8());
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi wxString fromAscii(const char *src)
|
__fi wxString fromAscii(const char* src)
|
||||||
{
|
{
|
||||||
return wxString::FromAscii(src);
|
return wxString::FromAscii(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString u128::ToString() const
|
wxString u128::ToString() const
|
||||||
{
|
{
|
||||||
return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString u128::ToString64() const
|
wxString u128::ToString64() const
|
||||||
{
|
{
|
||||||
return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString u128::ToString8() const
|
wxString u128::ToString8() const
|
||||||
{
|
{
|
||||||
FastFormatUnicode result;
|
FastFormatUnicode result;
|
||||||
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
|
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
|
||||||
for (uint i = 2; i < 16; i += 2)
|
for (uint i = 2; i < 16; i += 2)
|
||||||
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
|
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void u128::WriteTo(FastFormatAscii &dest) const
|
void u128::WriteTo(FastFormatAscii& dest) const
|
||||||
{
|
{
|
||||||
dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void u128::WriteTo64(FastFormatAscii &dest) const
|
void u128::WriteTo64(FastFormatAscii& dest) const
|
||||||
{
|
{
|
||||||
dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void u128::WriteTo8(FastFormatAscii &dest) const
|
void u128::WriteTo8(FastFormatAscii& dest) const
|
||||||
{
|
{
|
||||||
dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
|
dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
|
||||||
for (uint i = 2; i < 16; i += 2)
|
for (uint i = 2; i < 16; i += 2)
|
||||||
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
|
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits a string into parts and adds the parts into the given SafeList.
|
// Splits a string into parts and adds the parts into the given SafeList.
|
||||||
|
@ -78,11 +78,11 @@ void u128::WriteTo8(FastFormatAscii &dest) const
|
||||||
//
|
//
|
||||||
// Note: wxWidgets 2.9 / 3.0 has a wxSplit function, but we're using 2.8 so I had to make
|
// Note: wxWidgets 2.9 / 3.0 has a wxSplit function, but we're using 2.8 so I had to make
|
||||||
// my own.
|
// my own.
|
||||||
void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode)
|
void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode)
|
||||||
{
|
{
|
||||||
wxStringTokenizer parts(src, delims, mode);
|
wxStringTokenizer parts(src, delims, mode);
|
||||||
while (parts.HasMoreTokens())
|
while (parts.HasMoreTokens())
|
||||||
dest.Add(parts.GetNextToken());
|
dest.Add(parts.GetNextToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joins a list of strings into one larger string, using the given string concatenation
|
// Joins a list of strings into one larger string, using the given string concatenation
|
||||||
|
@ -91,32 +91,34 @@ void SplitString(wxArrayString &dest, const wxString &src, const wxString &delim
|
||||||
//
|
//
|
||||||
// Note: wxWidgets 2.9 / 3.0 has a wxJoin function, but we're using 2.8 so I had to make
|
// Note: wxWidgets 2.9 / 3.0 has a wxJoin function, but we're using 2.8 so I had to make
|
||||||
// my own.
|
// my own.
|
||||||
wxString JoinString(const wxArrayString &src, const wxString &separator)
|
wxString JoinString(const wxArrayString& src, const wxString& separator)
|
||||||
{
|
{
|
||||||
wxString dest;
|
wxString dest;
|
||||||
for (int i = 0, len = src.GetCount(); i < len; ++i) {
|
for (int i = 0, len = src.GetCount(); i < len; ++i)
|
||||||
if (src[i].IsEmpty())
|
{
|
||||||
continue;
|
if (src[i].IsEmpty())
|
||||||
if (!dest.IsEmpty())
|
continue;
|
||||||
dest += separator;
|
if (!dest.IsEmpty())
|
||||||
dest += src[i];
|
dest += separator;
|
||||||
}
|
dest += src[i];
|
||||||
return dest;
|
}
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString JoinString(const wxChar **src, const wxString &separator)
|
wxString JoinString(const wxChar** src, const wxString& separator)
|
||||||
{
|
{
|
||||||
wxString dest;
|
wxString dest;
|
||||||
while (*src != NULL) {
|
while (*src != NULL)
|
||||||
if (*src[0] == 0)
|
{
|
||||||
continue;
|
if (*src[0] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!dest.IsEmpty())
|
if (!dest.IsEmpty())
|
||||||
dest += separator;
|
dest += separator;
|
||||||
dest += *src;
|
dest += *src;
|
||||||
++src;
|
++src;
|
||||||
}
|
}
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,12 +129,12 @@ wxString JoinString(const wxChar **src, const wxString &separator)
|
||||||
// This, so far, include types such as wxPoint, wxRect, and wxSize.
|
// This, so far, include types such as wxPoint, wxRect, and wxSize.
|
||||||
//
|
//
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Parse(const wxString &src, const wxString &separators = L",")
|
T Parse(const wxString& src, const wxString& separators = L",")
|
||||||
{
|
{
|
||||||
T retval;
|
T retval;
|
||||||
if (!TryParse(retval, src, separators))
|
if (!TryParse(retval, src, separators))
|
||||||
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
|
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,104 +143,104 @@ T Parse(const wxString &src, const wxString &separators = L",")
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Converts a wxPoint into a comma-delimited string!
|
// Converts a wxPoint into a comma-delimited string!
|
||||||
wxString ToString(const wxPoint &src, const wxString &separator)
|
wxString ToString(const wxPoint& src, const wxString& separator)
|
||||||
{
|
{
|
||||||
return wxString() << src.x << separator << src.y;
|
return wxString() << src.x << separator << src.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString ToString(const wxSize &src, const wxString &separator)
|
wxString ToString(const wxSize& src, const wxString& separator)
|
||||||
{
|
{
|
||||||
return wxString() << src.GetWidth() << separator << src.GetHeight();
|
return wxString() << src.GetWidth() << separator << src.GetHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a wxRect into a comma-delimited string!
|
// Converts a wxRect into a comma-delimited string!
|
||||||
// Example: 32,64,128,5
|
// Example: 32,64,128,5
|
||||||
wxString ToString(const wxRect &src, const wxString &separator)
|
wxString ToString(const wxRect& src, const wxString& separator)
|
||||||
{
|
{
|
||||||
return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator);
|
return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Parse helpers for wxString!
|
// Parse helpers for wxString!
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool TryParse(wxPoint &dest, wxStringTokenizer &parts)
|
bool TryParse(wxPoint& dest, wxStringTokenizer& parts)
|
||||||
{
|
{
|
||||||
long result[2];
|
long result[2];
|
||||||
|
|
||||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||||
return false;
|
return false;
|
||||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||||
return false;
|
return false;
|
||||||
dest.x = result[0];
|
dest.x = result[0];
|
||||||
dest.y = result[1];
|
dest.y = result[1];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryParse(wxSize &dest, wxStringTokenizer &parts)
|
bool TryParse(wxSize& dest, wxStringTokenizer& parts)
|
||||||
{
|
{
|
||||||
long result[2];
|
long result[2];
|
||||||
|
|
||||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||||
return false;
|
return false;
|
||||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||||
return false;
|
return false;
|
||||||
dest.SetWidth(result[0]);
|
dest.SetWidth(result[0]);
|
||||||
dest.SetHeight(result[1]);
|
dest.SetHeight(result[1]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to parse the given string into a wxPoint value at 'dest.' If the parse fails, the
|
// Tries to parse the given string into a wxPoint value at 'dest.' If the parse fails, the
|
||||||
// method aborts and returns false.
|
// method aborts and returns false.
|
||||||
bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval, const wxString &separators)
|
bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval, const wxString& separators)
|
||||||
{
|
{
|
||||||
dest = defval;
|
dest = defval;
|
||||||
wxStringTokenizer parts(src, separators);
|
wxStringTokenizer parts(src, separators);
|
||||||
return TryParse(dest, parts);
|
return TryParse(dest, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval, const wxString &separators)
|
bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval, const wxString& separators)
|
||||||
{
|
{
|
||||||
dest = defval;
|
dest = defval;
|
||||||
wxStringTokenizer parts(src, separators);
|
wxStringTokenizer parts(src, separators);
|
||||||
return TryParse(dest, parts);
|
return TryParse(dest, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval, const wxString &separators)
|
bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval, const wxString& separators)
|
||||||
{
|
{
|
||||||
dest = defval;
|
dest = defval;
|
||||||
|
|
||||||
wxStringTokenizer parts(src, separators);
|
wxStringTokenizer parts(src, separators);
|
||||||
|
|
||||||
wxPoint point;
|
wxPoint point;
|
||||||
wxSize size;
|
wxSize size;
|
||||||
|
|
||||||
if (!TryParse(point, parts))
|
if (!TryParse(point, parts))
|
||||||
return false;
|
return false;
|
||||||
if (!TryParse(size, parts))
|
if (!TryParse(size, parts))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dest = wxRect(point, size);
|
dest = wxRect(point, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns TRUE if the parse is valid, or FALSE if it's a comment.
|
// returns TRUE if the parse is valid, or FALSE if it's a comment.
|
||||||
bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest)
|
bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest)
|
||||||
{
|
{
|
||||||
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
|
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
|
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
|
||||||
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
|
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
|
ParsedAssignmentString::ParsedAssignmentString(const wxString& src)
|
||||||
{
|
{
|
||||||
IsComment = pxParseAssignmentString(src, lvalue, rvalue);
|
IsComment = pxParseAssignmentString(src, lvalue, rvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
|
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
|
||||||
|
@ -249,37 +251,41 @@ ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
|
||||||
// from incoming data. Mac platforms may need an implementation of their own that converts
|
// from incoming data. Mac platforms may need an implementation of their own that converts
|
||||||
// newlines to CRs...?
|
// newlines to CRs...?
|
||||||
//
|
//
|
||||||
void px_fputs(FILE *fp, const char *src)
|
void px_fputs(FILE* fp, const char* src)
|
||||||
{
|
{
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Windows needs CR's partnered with all newlines, or else notepad.exe can't view
|
// Windows needs CR's partnered with all newlines, or else notepad.exe can't view
|
||||||
// the stupid logfile. Best way is to write one char at a time.. >_<
|
// the stupid logfile. Best way is to write one char at a time.. >_<
|
||||||
|
|
||||||
const char *curchar = src;
|
const char* curchar = src;
|
||||||
bool prevcr = false;
|
bool prevcr = false;
|
||||||
while (*curchar != 0) {
|
while (*curchar != 0)
|
||||||
if (*curchar == '\r') {
|
{
|
||||||
prevcr = true;
|
if (*curchar == '\r')
|
||||||
} else {
|
{
|
||||||
// Only write a CR/LF pair if the current LF is not prefixed nor
|
prevcr = true;
|
||||||
// post-fixed by a CR.
|
}
|
||||||
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
else
|
||||||
fputs("\r\n", fp);
|
{
|
||||||
else
|
// Only write a CR/LF pair if the current LF is not prefixed nor
|
||||||
fputc(*curchar, fp);
|
// post-fixed by a CR.
|
||||||
|
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
||||||
|
fputs("\r\n", fp);
|
||||||
|
else
|
||||||
|
fputc(*curchar, fp);
|
||||||
|
|
||||||
prevcr = false;
|
prevcr = false;
|
||||||
}
|
}
|
||||||
++curchar;
|
++curchar;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Linux is happy with plain old LFs. Not sure about Macs... does OSX still
|
// Linux is happy with plain old LFs. Not sure about Macs... does OSX still
|
||||||
// go by the old school Mac style of using Crs only?
|
// go by the old school Mac style of using Crs only?
|
||||||
|
|
||||||
fputs(src, fp); // fputs does not do automatic newlines, so it's ok!
|
fputs(src, fp); // fputs does not do automatic newlines, so it's ok!
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#define WX_STR(str) (str.wc_str())
|
#define WX_STR(str) (str.wc_str())
|
||||||
#else
|
#else
|
||||||
// Stupid wx3.0 doesn't support c_str for vararg function
|
// Stupid wx3.0 doesn't support c_str for vararg function
|
||||||
#define WX_STR(str) (static_cast<const char *>(str.c_str()))
|
#define WX_STR(str) (static_cast<const char*>(str.c_str()))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -33,59 +33,59 @@
|
||||||
// Converts a string to UTF8 and provides an interface for getting its length.
|
// Converts a string to UTF8 and provides an interface for getting its length.
|
||||||
class pxToUTF8
|
class pxToUTF8
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(pxToUTF8);
|
DeclareNoncopyableObject(pxToUTF8);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxCharBuffer m_result;
|
wxCharBuffer m_result;
|
||||||
int m_length;
|
int m_length;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit pxToUTF8(const wxString &src)
|
explicit pxToUTF8(const wxString& src)
|
||||||
: m_result(src.ToUTF8())
|
: m_result(src.ToUTF8())
|
||||||
{
|
{
|
||||||
m_length = -1;
|
m_length = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Length()
|
size_t Length()
|
||||||
{
|
{
|
||||||
if (-1 == m_length)
|
if (-1 == m_length)
|
||||||
m_length = strlen(m_result);
|
m_length = strlen(m_result);
|
||||||
return m_length;
|
return m_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Convert(const wxString &src)
|
void Convert(const wxString& src)
|
||||||
{
|
{
|
||||||
m_result = src.ToUTF8();
|
m_result = src.ToUTF8();
|
||||||
m_length = -1;
|
m_length = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *data() const { return m_result; }
|
const char* data() const { return m_result; }
|
||||||
|
|
||||||
operator const char *() const
|
operator const char*() const
|
||||||
{
|
{
|
||||||
return m_result.data();
|
return m_result.data();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void px_fputs(FILE *fp, const char *src);
|
extern void px_fputs(FILE* fp, const char* src);
|
||||||
|
|
||||||
// wxWidgets lacks one of its own...
|
// wxWidgets lacks one of its own...
|
||||||
extern const wxRect wxDefaultRect;
|
extern const wxRect wxDefaultRect;
|
||||||
|
|
||||||
extern void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL);
|
extern void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL);
|
||||||
extern wxString JoinString(const wxArrayString &src, const wxString &separator);
|
extern wxString JoinString(const wxArrayString& src, const wxString& separator);
|
||||||
extern wxString JoinString(const wxChar **src, const wxString &separator);
|
extern wxString JoinString(const wxChar** src, const wxString& separator);
|
||||||
|
|
||||||
extern wxString ToString(const wxPoint &src, const wxString &separator = L",");
|
extern wxString ToString(const wxPoint& src, const wxString& separator = L",");
|
||||||
extern wxString ToString(const wxSize &src, const wxString &separator = L",");
|
extern wxString ToString(const wxSize& src, const wxString& separator = L",");
|
||||||
extern wxString ToString(const wxRect &src, const wxString &separator = L",");
|
extern wxString ToString(const wxRect& src, const wxString& separator = L",");
|
||||||
|
|
||||||
extern bool TryParse(wxPoint &dest, const wxStringTokenizer &parts);
|
extern bool TryParse(wxPoint& dest, const wxStringTokenizer& parts);
|
||||||
extern bool TryParse(wxSize &dest, const wxStringTokenizer &parts);
|
extern bool TryParse(wxSize& dest, const wxStringTokenizer& parts);
|
||||||
|
|
||||||
extern bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval = wxDefaultPosition, const wxString &separators = L",");
|
extern bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval = wxDefaultPosition, const wxString& separators = L",");
|
||||||
extern bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval = wxDefaultSize, const wxString &separators = L",");
|
extern bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval = wxDefaultSize, const wxString& separators = L",");
|
||||||
extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = wxDefaultRect, const wxString &separators = L",");
|
extern bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval = wxDefaultRect, const wxString& separators = L",");
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ParsedAssignmentString
|
// ParsedAssignmentString
|
||||||
|
@ -103,11 +103,11 @@ extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = w
|
||||||
//
|
//
|
||||||
struct ParsedAssignmentString
|
struct ParsedAssignmentString
|
||||||
{
|
{
|
||||||
wxString lvalue;
|
wxString lvalue;
|
||||||
wxString rvalue;
|
wxString rvalue;
|
||||||
bool IsComment;
|
bool IsComment;
|
||||||
|
|
||||||
ParsedAssignmentString(const wxString &src);
|
ParsedAssignmentString(const wxString& src);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ======================================================================================
|
// ======================================================================================
|
||||||
|
@ -139,40 +139,40 @@ typedef ScopedAlignedAlloc<char, 16> CharBufferType;
|
||||||
class FastFormatAscii
|
class FastFormatAscii
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
CharBufferType m_dest;
|
CharBufferType m_dest;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastFormatAscii();
|
FastFormatAscii();
|
||||||
~FastFormatAscii() = default;
|
~FastFormatAscii() = default;
|
||||||
FastFormatAscii &Write(const char *fmt, ...);
|
FastFormatAscii& Write(const char* fmt, ...);
|
||||||
FastFormatAscii &WriteV(const char *fmt, va_list argptr);
|
FastFormatAscii& WriteV(const char* fmt, va_list argptr);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
bool IsEmpty() const;
|
bool IsEmpty() const;
|
||||||
|
|
||||||
const char *c_str() const { return m_dest.GetPtr(); }
|
const char* c_str() const { return m_dest.GetPtr(); }
|
||||||
operator const char *() const { return m_dest.GetPtr(); }
|
operator const char*() const { return m_dest.GetPtr(); }
|
||||||
|
|
||||||
const wxString GetString() const;
|
const wxString GetString() const;
|
||||||
//operator wxString() const;
|
//operator wxString() const;
|
||||||
|
|
||||||
FastFormatAscii &operator+=(const wxString &s)
|
FastFormatAscii& operator+=(const wxString& s)
|
||||||
{
|
{
|
||||||
Write("%s", WX_STR(s));
|
Write("%s", WX_STR(s));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatAscii &operator+=(const wxChar *psz)
|
FastFormatAscii& operator+=(const wxChar* psz)
|
||||||
{
|
{
|
||||||
Write("%ls", psz);
|
Write("%ls", psz);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatAscii &operator+=(const char *psz)
|
FastFormatAscii& operator+=(const char* psz)
|
||||||
{
|
{
|
||||||
Write("%s", psz);
|
Write("%s", psz);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -181,54 +181,54 @@ public:
|
||||||
class FastFormatUnicode
|
class FastFormatUnicode
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
CharBufferType m_dest;
|
CharBufferType m_dest;
|
||||||
uint m_Length;
|
uint m_Length;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastFormatUnicode();
|
FastFormatUnicode();
|
||||||
~FastFormatUnicode() = default;
|
~FastFormatUnicode() = default;
|
||||||
|
|
||||||
FastFormatUnicode &Write(const char *fmt, ...);
|
FastFormatUnicode& Write(const char* fmt, ...);
|
||||||
FastFormatUnicode &Write(const wxChar *fmt, ...);
|
FastFormatUnicode& Write(const wxChar* fmt, ...);
|
||||||
FastFormatUnicode &Write(const wxString fmt, ...);
|
FastFormatUnicode& Write(const wxString fmt, ...);
|
||||||
FastFormatUnicode &WriteV(const char *fmt, va_list argptr);
|
FastFormatUnicode& WriteV(const char* fmt, va_list argptr);
|
||||||
FastFormatUnicode &WriteV(const wxChar *fmt, va_list argptr);
|
FastFormatUnicode& WriteV(const wxChar* fmt, va_list argptr);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
bool IsEmpty() const;
|
bool IsEmpty() const;
|
||||||
uint Length() const { return m_Length; }
|
uint Length() const { return m_Length; }
|
||||||
|
|
||||||
FastFormatUnicode &ToUpper();
|
FastFormatUnicode& ToUpper();
|
||||||
FastFormatUnicode &ToLower();
|
FastFormatUnicode& ToLower();
|
||||||
|
|
||||||
const wxChar *c_str() const { return (const wxChar *)m_dest.GetPtr(); }
|
const wxChar* c_str() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||||
operator const wxChar *() const { return (const wxChar *)m_dest.GetPtr(); }
|
operator const wxChar*() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||||
operator wxString() const { return (const wxChar *)m_dest.GetPtr(); }
|
operator wxString() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||||
|
|
||||||
FastFormatUnicode &operator+=(const wxString &s)
|
FastFormatUnicode& operator+=(const wxString& s)
|
||||||
{
|
{
|
||||||
Write(L"%s", WX_STR(s));
|
Write(L"%s", WX_STR(s));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &operator+=(const wxChar *psz)
|
FastFormatUnicode& operator+=(const wxChar* psz)
|
||||||
{
|
{
|
||||||
Write(L"%s", psz);
|
Write(L"%s", psz);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFormatUnicode &operator+=(const char *psz);
|
FastFormatUnicode& operator+=(const char* psz);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest);
|
extern bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest);
|
||||||
|
|
||||||
#define pxsFmt FastFormatUnicode().Write
|
#define pxsFmt FastFormatUnicode().Write
|
||||||
#define pxsFmtV FastFormatUnicode().WriteV
|
#define pxsFmtV FastFormatUnicode().WriteV
|
||||||
|
|
||||||
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
|
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
|
||||||
|
|
||||||
extern wxString &operator+=(wxString &str1, const FastFormatUnicode &str2);
|
extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
|
||||||
extern wxString operator+(const wxString &str1, const FastFormatUnicode &str2);
|
extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
|
||||||
extern wxString operator+(const wxChar *str1, const FastFormatUnicode &str2);
|
extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);
|
||||||
extern wxString operator+(const FastFormatUnicode &str1, const wxString &str2);
|
extern wxString operator+(const FastFormatUnicode& str1, const wxString& str2);
|
||||||
extern wxString operator+(const FastFormatUnicode &str1, const wxChar *str2);
|
extern wxString operator+(const FastFormatUnicode& str1, const wxChar* str2);
|
||||||
|
|
|
@ -33,12 +33,12 @@ const wxTimeSpan Threading::def_yieldgui_interval(0, 0, 0, 100);
|
||||||
|
|
||||||
ConsoleLogSource_Threading::ConsoleLogSource_Threading()
|
ConsoleLogSource_Threading::ConsoleLogSource_Threading()
|
||||||
{
|
{
|
||||||
static const TraceLogDescriptor myDesc =
|
static const TraceLogDescriptor myDesc =
|
||||||
{
|
{
|
||||||
L"p&xThread", L"pxThread",
|
L"p&xThread", L"pxThread",
|
||||||
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
|
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
|
||||||
|
|
||||||
m_Descriptor = &myDesc;
|
m_Descriptor = &myDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleLogSource_Threading pxConLog_Thread;
|
ConsoleLogSource_Threading pxConLog_Thread;
|
||||||
|
@ -47,18 +47,18 @@ ConsoleLogSource_Threading pxConLog_Thread;
|
||||||
class StaticMutex : public Mutex
|
class StaticMutex : public Mutex
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool &m_DeletedFlag;
|
bool& m_DeletedFlag;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StaticMutex(bool &deletedFlag)
|
StaticMutex(bool& deletedFlag)
|
||||||
: m_DeletedFlag(deletedFlag)
|
: m_DeletedFlag(deletedFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~StaticMutex()
|
virtual ~StaticMutex()
|
||||||
{
|
{
|
||||||
m_DeletedFlag = true;
|
m_DeletedFlag = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static pthread_key_t curthread_key = 0;
|
static pthread_key_t curthread_key = 0;
|
||||||
|
@ -67,111 +67,115 @@ static s32 total_key_count = 0;
|
||||||
static bool tkl_destructed = false;
|
static bool tkl_destructed = false;
|
||||||
static StaticMutex total_key_lock(tkl_destructed);
|
static StaticMutex total_key_lock(tkl_destructed);
|
||||||
|
|
||||||
static void make_curthread_key(const pxThread *thr)
|
static void make_curthread_key(const pxThread* thr)
|
||||||
{
|
{
|
||||||
pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key.");
|
pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key.");
|
||||||
|
|
||||||
ScopedLock lock(total_key_lock);
|
ScopedLock lock(total_key_lock);
|
||||||
if (total_key_count++ != 0)
|
if (total_key_count++ != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (0 != pthread_key_create(&curthread_key, NULL)) {
|
if (0 != pthread_key_create(&curthread_key, NULL))
|
||||||
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
{
|
||||||
curthread_key = 0;
|
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
||||||
}
|
curthread_key = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unmake_curthread_key()
|
static void unmake_curthread_key()
|
||||||
{
|
{
|
||||||
ScopedLock lock;
|
ScopedLock lock;
|
||||||
if (!tkl_destructed)
|
if (!tkl_destructed)
|
||||||
lock.AssignAndLock(total_key_lock);
|
lock.AssignAndLock(total_key_lock);
|
||||||
|
|
||||||
if (--total_key_count > 0)
|
if (--total_key_count > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (curthread_key)
|
if (curthread_key)
|
||||||
pthread_key_delete(curthread_key);
|
pthread_key_delete(curthread_key);
|
||||||
|
|
||||||
curthread_key = 0;
|
curthread_key = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxTestCancel()
|
void Threading::pxTestCancel()
|
||||||
{
|
{
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a handle to the current persistent thread. If the current thread does not belong
|
// Returns a handle to the current persistent thread. If the current thread does not belong
|
||||||
// to the pxThread table, NULL is returned. Since the main/ui thread is not created
|
// to the pxThread table, NULL is returned. Since the main/ui thread is not created
|
||||||
// through pxThread it will also return NULL. Callers can use wxThread::IsMain() to
|
// through pxThread it will also return NULL. Callers can use wxThread::IsMain() to
|
||||||
// test if the NULL thread is the main thread.
|
// test if the NULL thread is the main thread.
|
||||||
pxThread *Threading::pxGetCurrentThread()
|
pxThread* Threading::pxGetCurrentThread()
|
||||||
{
|
{
|
||||||
return !curthread_key ? NULL : (pxThread *)pthread_getspecific(curthread_key);
|
return !curthread_key ? NULL : (pxThread*)pthread_getspecific(curthread_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the name of the current thread, or "Unknown" if the thread is neither a pxThread
|
// returns the name of the current thread, or "Unknown" if the thread is neither a pxThread
|
||||||
// nor the Main/UI thread.
|
// nor the Main/UI thread.
|
||||||
wxString Threading::pxGetCurrentThreadName()
|
wxString Threading::pxGetCurrentThreadName()
|
||||||
{
|
{
|
||||||
if (pxThread *thr = pxGetCurrentThread()) {
|
if (pxThread* thr = pxGetCurrentThread())
|
||||||
return thr->GetName();
|
{
|
||||||
} else if (wxThread::IsMain()) {
|
return thr->GetName();
|
||||||
return L"Main/UI";
|
}
|
||||||
}
|
else if (wxThread::IsMain())
|
||||||
|
{
|
||||||
|
return L"Main/UI";
|
||||||
|
}
|
||||||
|
|
||||||
return L"Unknown";
|
return L"Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxYield(int ms)
|
void Threading::pxYield(int ms)
|
||||||
{
|
{
|
||||||
if (pxThread *thr = pxGetCurrentThread())
|
if (pxThread* thr = pxGetCurrentThread())
|
||||||
thr->Yield(ms);
|
thr->Yield(ms);
|
||||||
else
|
else
|
||||||
Sleep(ms);
|
Sleep(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (intended for internal use only)
|
// (intended for internal use only)
|
||||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||||
// handled via normal yielding methods.
|
// handled via normal yielding methods.
|
||||||
bool Threading::_WaitGui_RecursionGuard(const wxChar *name)
|
bool Threading::_WaitGui_RecursionGuard(const wxChar* name)
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
|
|
||||||
// In order to avoid deadlock we need to make sure we cut some time to handle messages.
|
// In order to avoid deadlock we need to make sure we cut some time to handle messages.
|
||||||
// But this can result in recursive yield calls, which would crash the app. Protect
|
// But this can result in recursive yield calls, which would crash the app. Protect
|
||||||
// against them here and, if recursion is detected, perform a standard blocking wait.
|
// against them here and, if recursion is detected, perform a standard blocking wait.
|
||||||
|
|
||||||
static int __Guard = 0;
|
static int __Guard = 0;
|
||||||
RecursionGuard guard(__Guard);
|
RecursionGuard guard(__Guard);
|
||||||
|
|
||||||
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
|
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
|
||||||
|
|
||||||
if (!guard.IsReentrant())
|
if (!guard.IsReentrant())
|
||||||
return false;
|
return false;
|
||||||
pxThreadLog.Write(pxGetCurrentThreadName(),
|
pxThreadLog.Write(pxGetCurrentThreadName(),
|
||||||
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
|
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void Threading::Timeslice()
|
__fi void Threading::Timeslice()
|
||||||
{
|
{
|
||||||
sched_yield();
|
sched_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_pt_callback_cleanup(void *handle)
|
void Threading::pxThread::_pt_callback_cleanup(void* handle)
|
||||||
{
|
{
|
||||||
((pxThread *)handle)->_ThreadCleanup();
|
((pxThread*)handle)->_ThreadCleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Threading::pxThread::pxThread(const wxString &name)
|
Threading::pxThread::pxThread(const wxString& name)
|
||||||
: m_name(name)
|
: m_name(name)
|
||||||
, m_thread()
|
, m_thread()
|
||||||
, m_native_id(0)
|
, m_native_id(0)
|
||||||
, m_native_handle(0)
|
, m_native_handle(0)
|
||||||
, m_detached(true) // start out with m_thread in detached/invalid state
|
, m_detached(true) // start out with m_thread in detached/invalid state
|
||||||
, m_running(false)
|
, m_running(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,50 +188,53 @@ Threading::pxThread::pxThread(const wxString &name)
|
||||||
// like marrying your sister, and then cheating on her with your daughter.
|
// like marrying your sister, and then cheating on her with your daughter.
|
||||||
Threading::pxThread::~pxThread()
|
Threading::pxThread::~pxThread()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
{
|
||||||
|
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
||||||
|
|
||||||
if (m_running) {
|
if (m_running)
|
||||||
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
{
|
||||||
m_mtx_InThread.Wait();
|
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
||||||
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
m_mtx_InThread.Wait();
|
||||||
}
|
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
||||||
Threading::Sleep(1);
|
}
|
||||||
Detach();
|
Threading::Sleep(1);
|
||||||
}
|
Detach();
|
||||||
DESTRUCTOR_CATCHALL
|
}
|
||||||
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const
|
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const
|
||||||
{
|
{
|
||||||
if (IsSelf())
|
if (IsSelf())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (IsDevBuild)
|
if (IsDevBuild)
|
||||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
|
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const
|
bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const
|
||||||
{
|
{
|
||||||
if (!IsSelf())
|
if (!IsSelf())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (IsDevBuild)
|
if (IsDevBuild)
|
||||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
|
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::FrankenMutex(Mutex &mutex)
|
void Threading::pxThread::FrankenMutex(Mutex& mutex)
|
||||||
{
|
{
|
||||||
if (mutex.RecreateIfLocked()) {
|
if (mutex.RecreateIfLocked())
|
||||||
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
{
|
||||||
// Let's create a new mutex lock to replace it.
|
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
||||||
|
// Let's create a new mutex lock to replace it.
|
||||||
|
|
||||||
pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!");
|
pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main entry point for starting or e-starting a persistent thread. This function performs necessary
|
// Main entry point for starting or e-starting a persistent thread. This function performs necessary
|
||||||
|
@ -238,53 +245,56 @@ void Threading::pxThread::FrankenMutex(Mutex &mutex)
|
||||||
// This function should not be called from the owner thread.
|
// This function should not be called from the owner thread.
|
||||||
void Threading::pxThread::Start()
|
void Threading::pxThread::Start()
|
||||||
{
|
{
|
||||||
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
||||||
ScopedLock startlock(m_mtx_start);
|
ScopedLock startlock(m_mtx_start);
|
||||||
if (m_running) {
|
if (m_running)
|
||||||
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
{
|
||||||
return;
|
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Detach(); // clean up previous thread handle, if one exists.
|
Detach(); // clean up previous thread handle, if one exists.
|
||||||
OnStart();
|
OnStart();
|
||||||
|
|
||||||
m_except = NULL;
|
m_except = NULL;
|
||||||
|
|
||||||
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
|
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
|
||||||
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
|
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
|
||||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
|
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
|
||||||
|
|
||||||
#ifdef ASAN_WORKAROUND
|
#ifdef ASAN_WORKAROUND
|
||||||
// Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982
|
// Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982
|
||||||
//
|
//
|
||||||
// In our case, the semaphore was posted (counter is 1) but thread is still
|
// In our case, the semaphore was posted (counter is 1) but thread is still
|
||||||
// waiting... So waits 100ms and checks the counter value manually
|
// waiting... So waits 100ms and checks the counter value manually
|
||||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100))) {
|
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100)))
|
||||||
if (m_sem_startup.Count() == 0)
|
{
|
||||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
if (m_sem_startup.Count() == 0)
|
||||||
}
|
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0))) {
|
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0)))
|
||||||
RethrowException();
|
{
|
||||||
|
RethrowException();
|
||||||
|
|
||||||
// And if the thread threw nothing of its own:
|
// And if the thread threw nothing of its own:
|
||||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
||||||
// sense that it stalls the calling thread completely until the new thread is created
|
// sense that it stalls the calling thread completely until the new thread is created
|
||||||
// (which may not always be desirable). But too bad. In order to safely use 'running' locks
|
// (which may not always be desirable). But too bad. In order to safely use 'running' locks
|
||||||
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't
|
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't
|
||||||
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
|
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
|
||||||
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
|
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
|
||||||
// overhead in starting threads).
|
// overhead in starting threads).
|
||||||
|
|
||||||
// (this could also be done using operating system specific calls, since any threaded OS has
|
// (this could also be done using operating system specific calls, since any threaded OS has
|
||||||
// functions that allow us to see if a thread is running or not, and to block against it even if
|
// functions that allow us to see if a thread is running or not, and to block against it even if
|
||||||
// it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But
|
// it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But
|
||||||
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
|
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
|
||||||
// possible to safely block against a running thread)
|
// possible to safely block against a running thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
||||||
|
@ -292,26 +302,27 @@ void Threading::pxThread::Start()
|
||||||
// This function should not be called from the owner thread.
|
// This function should not be called from the owner thread.
|
||||||
bool Threading::pxThread::Detach()
|
bool Threading::pxThread::Detach()
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
|
|
||||||
if (m_detached.exchange(true))
|
if (m_detached.exchange(true))
|
||||||
return false;
|
return false;
|
||||||
pthread_detach(m_thread);
|
pthread_detach(m_thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::_basecancel()
|
bool Threading::pxThread::_basecancel()
|
||||||
{
|
{
|
||||||
if (!m_running)
|
if (!m_running)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_detached) {
|
if (m_detached)
|
||||||
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
{
|
||||||
return false;
|
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_cancel(m_thread);
|
pthread_cancel(m_thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remarks:
|
// Remarks:
|
||||||
|
@ -330,34 +341,35 @@ bool Threading::pxThread::_basecancel()
|
||||||
//
|
//
|
||||||
void Threading::pxThread::Cancel(bool isBlocking)
|
void Threading::pxThread::Cancel(bool isBlocking)
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
|
|
||||||
// Prevent simultaneous startup and cancel, necessary to avoid
|
// Prevent simultaneous startup and cancel, necessary to avoid
|
||||||
ScopedLock startlock(m_mtx_start);
|
ScopedLock startlock(m_mtx_start);
|
||||||
|
|
||||||
if (!_basecancel())
|
if (!_basecancel())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isBlocking) {
|
if (isBlocking)
|
||||||
WaitOnSelf(m_mtx_InThread);
|
{
|
||||||
Detach();
|
WaitOnSelf(m_mtx_InThread);
|
||||||
}
|
Detach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::Cancel(const wxTimeSpan ×pan)
|
bool Threading::pxThread::Cancel(const wxTimeSpan& timespan)
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
|
|
||||||
// Prevent simultaneous startup and cancel:
|
// Prevent simultaneous startup and cancel:
|
||||||
ScopedLock startlock(m_mtx_start);
|
ScopedLock startlock(m_mtx_start);
|
||||||
|
|
||||||
if (!_basecancel())
|
if (!_basecancel())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!WaitOnSelf(m_mtx_InThread, timespan))
|
if (!WaitOnSelf(m_mtx_InThread, timespan))
|
||||||
return false;
|
return false;
|
||||||
Detach();
|
Detach();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,32 +385,32 @@ bool Threading::pxThread::Cancel(const wxTimeSpan ×pan)
|
||||||
//
|
//
|
||||||
void Threading::pxThread::Block()
|
void Threading::pxThread::Block()
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
WaitOnSelf(m_mtx_InThread);
|
WaitOnSelf(m_mtx_InThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::Block(const wxTimeSpan &timeout)
|
bool Threading::pxThread::Block(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
return WaitOnSelf(m_mtx_InThread, timeout);
|
return WaitOnSelf(m_mtx_InThread, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::IsSelf() const
|
bool Threading::pxThread::IsSelf() const
|
||||||
{
|
{
|
||||||
// Detached threads may have their pthread handles recycled as newer threads, causing
|
// Detached threads may have their pthread handles recycled as newer threads, causing
|
||||||
// false IsSelf reports.
|
// false IsSelf reports.
|
||||||
return !m_detached && (pthread_self() == m_thread);
|
return !m_detached && (pthread_self() == m_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::IsRunning() const
|
bool Threading::pxThread::IsRunning() const
|
||||||
{
|
{
|
||||||
return m_running;
|
return m_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::AddListener(EventListener_Thread &evt)
|
void Threading::pxThread::AddListener(EventListener_Thread& evt)
|
||||||
{
|
{
|
||||||
evt.SetThread(this);
|
evt.SetThread(this);
|
||||||
m_evtsrc_OnDelete.Add(evt);
|
m_evtsrc_OnDelete.Add(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
|
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
|
||||||
|
@ -406,49 +418,51 @@ void Threading::pxThread::AddListener(EventListener_Thread &evt)
|
||||||
// the thread will have allowed itself to terminate properly.
|
// the thread will have allowed itself to terminate properly.
|
||||||
void Threading::pxThread::RethrowException() const
|
void Threading::pxThread::RethrowException() const
|
||||||
{
|
{
|
||||||
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
|
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
|
||||||
// pointer might still be invalid after detachment, so might as well just detach and check
|
// pointer might still be invalid after detachment, so might as well just detach and check
|
||||||
// after.
|
// after.
|
||||||
|
|
||||||
ScopedExcept ptr(const_cast<pxThread *>(this)->m_except.DetachPtr());
|
ScopedExcept ptr(const_cast<pxThread*>(this)->m_except.DetachPtr());
|
||||||
if (ptr)
|
if (ptr)
|
||||||
ptr->Rethrow();
|
ptr->Rethrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool m_BlockDeletions = false;
|
static bool m_BlockDeletions = false;
|
||||||
|
|
||||||
bool Threading::AllowDeletions()
|
bool Threading::AllowDeletions()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
return !m_BlockDeletions;
|
return !m_BlockDeletions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::YieldToMain()
|
void Threading::YieldToMain()
|
||||||
{
|
{
|
||||||
m_BlockDeletions = true;
|
m_BlockDeletions = true;
|
||||||
wxTheApp->Yield(true);
|
wxTheApp->Yield(true);
|
||||||
m_BlockDeletions = false;
|
m_BlockDeletions = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_selfRunningTest(const wxChar *name) const
|
void Threading::pxThread::_selfRunningTest(const wxChar* name) const
|
||||||
{
|
{
|
||||||
if (HasPendingException()) {
|
if (HasPendingException())
|
||||||
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
{
|
||||||
RethrowException();
|
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
||||||
}
|
RethrowException();
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_running) {
|
if (!m_running)
|
||||||
throw Exception::CancelEvent(pxsFmt(
|
{
|
||||||
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
throw Exception::CancelEvent(pxsFmt(
|
||||||
WX_STR(GetName()), name));
|
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
||||||
}
|
WX_STR(GetName()), name));
|
||||||
|
}
|
||||||
|
|
||||||
// Thread is still alive and kicking (for now) -- yield to other messages and hope
|
// Thread is still alive and kicking (for now) -- yield to other messages and hope
|
||||||
// that impending chaos does not ensue. [it shouldn't since we block pxThread
|
// that impending chaos does not ensue. [it shouldn't since we block pxThread
|
||||||
// objects from being deleted until outside the scope of a mutex/semaphore wait).
|
// objects from being deleted until outside the scope of a mutex/semaphore wait).
|
||||||
|
|
||||||
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
|
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
|
||||||
Threading::YieldToMain();
|
Threading::YieldToMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This helper function is a deadlock-safe method of waiting on a semaphore in a pxThread. If the
|
// This helper function is a deadlock-safe method of waiting on a semaphore in a pxThread. If the
|
||||||
|
@ -462,16 +476,17 @@ void Threading::pxThread::_selfRunningTest(const wxChar *name) const
|
||||||
// This function will rethrow exceptions raised by the persistent thread, if it throws an error
|
// This function will rethrow exceptions raised by the persistent thread, if it throws an error
|
||||||
// while the calling thread is blocking (which also means the persistent thread has terminated).
|
// while the calling thread is blocking (which also means the persistent thread has terminated).
|
||||||
//
|
//
|
||||||
void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
|
void Threading::pxThread::WaitOnSelf(Semaphore& sem) const
|
||||||
{
|
{
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
{
|
||||||
return;
|
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||||
_selfRunningTest(L"semaphore");
|
return;
|
||||||
}
|
_selfRunningTest(L"semaphore");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This helper function is a deadlock-safe method of waiting on a mutex in a pxThread.
|
// This helper function is a deadlock-safe method of waiting on a mutex in a pxThread.
|
||||||
|
@ -487,52 +502,55 @@ void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
|
||||||
// error while the calling thread is blocking (which also means the persistent thread has
|
// error while the calling thread is blocking (which also means the persistent thread has
|
||||||
// terminated).
|
// terminated).
|
||||||
//
|
//
|
||||||
void Threading::pxThread::WaitOnSelf(Mutex &mutex) const
|
void Threading::pxThread::WaitOnSelf(Mutex& mutex) const
|
||||||
{
|
{
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
{
|
||||||
return;
|
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||||
_selfRunningTest(L"mutex");
|
return;
|
||||||
}
|
_selfRunningTest(L"mutex");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const wxTimeSpan SelfWaitInterval(0, 0, 0, 333);
|
static const wxTimeSpan SelfWaitInterval(0, 0, 0, 333);
|
||||||
|
|
||||||
bool Threading::pxThread::WaitOnSelf(Semaphore &sem, const wxTimeSpan &timeout) const
|
bool Threading::pxThread::WaitOnSelf(Semaphore& sem, const wxTimeSpan& timeout) const
|
||||||
{
|
{
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
wxTimeSpan runningout(timeout);
|
wxTimeSpan runningout(timeout);
|
||||||
|
|
||||||
while (runningout.GetMilliseconds() > 0) {
|
while (runningout.GetMilliseconds() > 0)
|
||||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
{
|
||||||
if (sem.WaitWithoutYield(interval))
|
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||||
return true;
|
if (sem.WaitWithoutYield(interval))
|
||||||
_selfRunningTest(L"semaphore");
|
return true;
|
||||||
runningout -= interval;
|
_selfRunningTest(L"semaphore");
|
||||||
}
|
runningout -= interval;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const
|
bool Threading::pxThread::WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const
|
||||||
{
|
{
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
wxTimeSpan runningout(timeout);
|
wxTimeSpan runningout(timeout);
|
||||||
|
|
||||||
while (runningout.GetMilliseconds() > 0) {
|
while (runningout.GetMilliseconds() > 0)
|
||||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
{
|
||||||
if (mutex.WaitWithoutYield(interval))
|
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||||
return true;
|
if (mutex.WaitWithoutYield(interval))
|
||||||
_selfRunningTest(L"mutex");
|
return true;
|
||||||
runningout -= interval;
|
_selfRunningTest(L"mutex");
|
||||||
}
|
runningout -= interval;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a thread cancellation point. If the thread has received a cancel request, this
|
// Inserts a thread cancellation point. If the thread has received a cancel request, this
|
||||||
|
@ -541,36 +559,39 @@ bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) co
|
||||||
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
|
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
|
||||||
void Threading::pxThread::TestCancel() const
|
void Threading::pxThread::TestCancel() const
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes the virtual member method
|
// Executes the virtual member method
|
||||||
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
(this->*method)();
|
{
|
||||||
}
|
(this->*method)();
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Neat repackaging for STL Runtime errors...
|
// Neat repackaging for STL Runtime errors...
|
||||||
//
|
//
|
||||||
catch (std::runtime_error &ex) {
|
catch (std::runtime_error& ex)
|
||||||
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
{
|
||||||
}
|
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch (Exception::RuntimeError &ex) {
|
catch (Exception::RuntimeError& ex)
|
||||||
BaseException *woot = ex.Clone();
|
{
|
||||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
BaseException* woot = ex.Clone();
|
||||||
m_except = woot;
|
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||||
}
|
m_except = woot;
|
||||||
|
}
|
||||||
#ifndef PCSX2_DEVBUILD
|
#ifndef PCSX2_DEVBUILD
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
||||||
// useful coming out of the core STL libraries anyway, and these are best handled by
|
// useful coming out of the core STL libraries anyway, and these are best handled by
|
||||||
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||||
/*catch( std::logic_error& ex )
|
/*catch( std::logic_error& ex )
|
||||||
{
|
{
|
||||||
throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s",
|
throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s",
|
||||||
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
||||||
|
@ -582,14 +603,15 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||||
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
||||||
);
|
);
|
||||||
}*/
|
}*/
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// BaseException -- same deal as LogicErrors.
|
// BaseException -- same deal as LogicErrors.
|
||||||
//
|
//
|
||||||
catch (BaseException &ex) {
|
catch (BaseException& ex)
|
||||||
BaseException *woot = ex.Clone();
|
{
|
||||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
BaseException* woot = ex.Clone();
|
||||||
m_except = woot;
|
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||||
}
|
m_except = woot;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,25 +619,25 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||||
// OnCleanupInThread() to extend cleanup functionality.
|
// OnCleanupInThread() to extend cleanup functionality.
|
||||||
void Threading::pxThread::_ThreadCleanup()
|
void Threading::pxThread::_ThreadCleanup()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||||
_try_virtual_invoke(&pxThread::OnCleanupInThread);
|
_try_virtual_invoke(&pxThread::OnCleanupInThread);
|
||||||
m_mtx_InThread.Release();
|
m_mtx_InThread.Release();
|
||||||
|
|
||||||
// Must set m_running LAST, as thread destructors depend on this value (it is used
|
// Must set m_running LAST, as thread destructors depend on this value (it is used
|
||||||
// to avoid destruction of the thread until all internal data use has stopped.
|
// to avoid destruction of the thread until all internal data use has stopped.
|
||||||
m_running = false;
|
m_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Threading::pxThread::GetName() const
|
wxString Threading::pxThread::GetName() const
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_mtx_ThreadName);
|
ScopedLock lock(m_mtx_ThreadName);
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::SetName(const wxString &newname)
|
void Threading::pxThread::SetName(const wxString& newname)
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_mtx_ThreadName);
|
ScopedLock lock(m_mtx_ThreadName);
|
||||||
m_name = newname;
|
m_name = newname;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This override is called by PeristentThread when the thread is first created, prior to
|
// This override is called by PeristentThread when the thread is first created, prior to
|
||||||
|
@ -627,82 +649,82 @@ void Threading::pxThread::SetName(const wxString &newname)
|
||||||
//
|
//
|
||||||
void Threading::pxThread::OnStartInThread()
|
void Threading::pxThread::OnStartInThread()
|
||||||
{
|
{
|
||||||
m_detached = false;
|
m_detached = false;
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
|
||||||
_platform_specific_OnStartInThread();
|
_platform_specific_OnStartInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_internal_execute()
|
void Threading::pxThread::_internal_execute()
|
||||||
{
|
{
|
||||||
m_mtx_InThread.Acquire();
|
m_mtx_InThread.Acquire();
|
||||||
|
|
||||||
_DoSetThreadName(GetName());
|
_DoSetThreadName(GetName());
|
||||||
make_curthread_key(this);
|
make_curthread_key(this);
|
||||||
if (curthread_key)
|
if (curthread_key)
|
||||||
pthread_setspecific(curthread_key, this);
|
pthread_setspecific(curthread_key, this);
|
||||||
|
|
||||||
OnStartInThread();
|
OnStartInThread();
|
||||||
m_sem_startup.Post();
|
m_sem_startup.Post();
|
||||||
|
|
||||||
_try_virtual_invoke(&pxThread::ExecuteTaskInThread);
|
_try_virtual_invoke(&pxThread::ExecuteTaskInThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by Start, prior to actual starting of the thread, and after any previous
|
// Called by Start, prior to actual starting of the thread, and after any previous
|
||||||
// running thread has been canceled or detached.
|
// running thread has been canceled or detached.
|
||||||
void Threading::pxThread::OnStart()
|
void Threading::pxThread::OnStart()
|
||||||
{
|
{
|
||||||
m_native_handle = 0;
|
m_native_handle = 0;
|
||||||
m_native_id = 0;
|
m_native_id = 0;
|
||||||
|
|
||||||
FrankenMutex(m_mtx_InThread);
|
FrankenMutex(m_mtx_InThread);
|
||||||
m_sem_event.Reset();
|
m_sem_event.Reset();
|
||||||
m_sem_startup.Reset();
|
m_sem_startup.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extending classes that override this method should always call it last from their
|
// Extending classes that override this method should always call it last from their
|
||||||
// personal implementations.
|
// personal implementations.
|
||||||
void Threading::pxThread::OnCleanupInThread()
|
void Threading::pxThread::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
if (curthread_key)
|
if (curthread_key)
|
||||||
pthread_setspecific(curthread_key, NULL);
|
pthread_setspecific(curthread_key, NULL);
|
||||||
|
|
||||||
unmake_curthread_key();
|
unmake_curthread_key();
|
||||||
|
|
||||||
_platform_specific_OnCleanupInThread();
|
_platform_specific_OnCleanupInThread();
|
||||||
|
|
||||||
m_native_handle = 0;
|
m_native_handle = 0;
|
||||||
m_native_id = 0;
|
m_native_id = 0;
|
||||||
|
|
||||||
m_evtsrc_OnDelete.Dispatch(0);
|
m_evtsrc_OnDelete.Dispatch(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
||||||
// callback function
|
// callback function
|
||||||
void *Threading::pxThread::_internal_callback(void *itsme)
|
void* Threading::pxThread::_internal_callback(void* itsme)
|
||||||
{
|
{
|
||||||
if (!pxAssertDev(itsme != NULL, wxNullChar))
|
if (!pxAssertDev(itsme != NULL, wxNullChar))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
internal_callback_helper(itsme);
|
internal_callback_helper(itsme);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// __try is used in pthread_cleanup_push when CLEANUP_SEH is used as the cleanup model.
|
// __try is used in pthread_cleanup_push when CLEANUP_SEH is used as the cleanup model.
|
||||||
// That can't be used in a function that has objects that require unwinding (compile
|
// That can't be used in a function that has objects that require unwinding (compile
|
||||||
// error C2712), so move it into a separate function.
|
// error C2712), so move it into a separate function.
|
||||||
void Threading::pxThread::internal_callback_helper(void *itsme)
|
void Threading::pxThread::internal_callback_helper(void* itsme)
|
||||||
{
|
{
|
||||||
pxThread &owner = *static_cast<pxThread *>(itsme);
|
pxThread& owner = *static_cast<pxThread*>(itsme);
|
||||||
|
|
||||||
pthread_cleanup_push(_pt_callback_cleanup, itsme);
|
pthread_cleanup_push(_pt_callback_cleanup, itsme);
|
||||||
owner._internal_execute();
|
owner._internal_execute();
|
||||||
pthread_cleanup_pop(true);
|
pthread_cleanup_pop(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_DoSetThreadName(const wxString &name)
|
void Threading::pxThread::_DoSetThreadName(const wxString& name)
|
||||||
{
|
{
|
||||||
_DoSetThreadName(static_cast<const char *>(name.ToUTF8()));
|
_DoSetThreadName(static_cast<const char*>(name.ToUTF8()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -746,23 +768,23 @@ void Threading::WaitEvent::Wait()
|
||||||
|
|
||||||
wxString Exception::BaseThreadError::FormatDiagnosticMessage() const
|
wxString Exception::BaseThreadError::FormatDiagnosticMessage() const
|
||||||
{
|
{
|
||||||
wxString null_str(L"Null Thread Object");
|
wxString null_str(L"Null Thread Object");
|
||||||
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Exception::BaseThreadError::FormatDisplayMessage() const
|
wxString Exception::BaseThreadError::FormatDisplayMessage() const
|
||||||
{
|
{
|
||||||
wxString null_str(L"Null Thread Object");
|
wxString null_str(L"Null Thread Object");
|
||||||
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pxThread &Exception::BaseThreadError::Thread()
|
pxThread& Exception::BaseThreadError::Thread()
|
||||||
{
|
{
|
||||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||||
return *m_thread;
|
return *m_thread;
|
||||||
}
|
}
|
||||||
const pxThread &Exception::BaseThreadError::Thread() const
|
const pxThread& Exception::BaseThreadError::Thread() const
|
||||||
{
|
{
|
||||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||||
return *m_thread;
|
return *m_thread;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#undef Yield // release the burden of windows.h global namespace spam.
|
#undef Yield // release the burden of windows.h global namespace spam.
|
||||||
|
|
||||||
#define AffinityAssert_AllowFrom_MainUI() \
|
#define AffinityAssert_AllowFrom_MainUI() \
|
||||||
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
|
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxThreadLog / ConsoleLogSource_Threading
|
// pxThreadLog / ConsoleLogSource_Threading
|
||||||
|
@ -40,25 +40,25 @@
|
||||||
|
|
||||||
class ConsoleLogSource_Threading : ConsoleLogSource
|
class ConsoleLogSource_Threading : ConsoleLogSource
|
||||||
{
|
{
|
||||||
typedef ConsoleLogSource _parent;
|
typedef ConsoleLogSource _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using _parent::IsActive;
|
using _parent::IsActive;
|
||||||
|
|
||||||
ConsoleLogSource_Threading();
|
ConsoleLogSource_Threading();
|
||||||
|
|
||||||
bool Write(const wxString &thrname, const wxChar *msg)
|
bool Write(const wxString& thrname, const wxChar* msg)
|
||||||
{
|
{
|
||||||
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||||
}
|
}
|
||||||
bool Warn(const wxString &thrname, const wxChar *msg)
|
bool Warn(const wxString& thrname, const wxChar* msg)
|
||||||
{
|
{
|
||||||
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||||
}
|
}
|
||||||
bool Error(const wxString &thrname, const wxChar *msg)
|
bool Error(const wxString& thrname, const wxChar* msg)
|
||||||
{
|
{
|
||||||
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ConsoleLogSource_Threading pxConLog_Thread;
|
extern ConsoleLogSource_Threading pxConLog_Thread;
|
||||||
|
@ -88,97 +88,97 @@ class wxTimeSpan;
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
class pxThread;
|
class pxThread;
|
||||||
class RwMutex;
|
class RwMutex;
|
||||||
|
|
||||||
extern void pxTestCancel();
|
extern void pxTestCancel();
|
||||||
extern pxThread *pxGetCurrentThread();
|
extern pxThread* pxGetCurrentThread();
|
||||||
extern wxString pxGetCurrentThreadName();
|
extern wxString pxGetCurrentThreadName();
|
||||||
extern u64 GetThreadCpuTime();
|
extern u64 GetThreadCpuTime();
|
||||||
extern u64 GetThreadTicksPerSecond();
|
extern u64 GetThreadTicksPerSecond();
|
||||||
|
|
||||||
// Yields the current thread and provides cancellation points if the thread is managed by
|
// Yields the current thread and provides cancellation points if the thread is managed by
|
||||||
// pxThread. Unmanaged threads use standard Sleep.
|
// pxThread. Unmanaged threads use standard Sleep.
|
||||||
extern void pxYield(int ms);
|
extern void pxYield(int ms);
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
class BaseThreadError : public RuntimeError
|
class BaseThreadError : public RuntimeError
|
||||||
{
|
{
|
||||||
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
|
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
|
||||||
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
|
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Threading::pxThread *m_thread;
|
Threading::pxThread* m_thread;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BaseThreadError()
|
BaseThreadError()
|
||||||
{
|
{
|
||||||
m_thread = NULL;
|
m_thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BaseThreadError(Threading::pxThread *_thread)
|
explicit BaseThreadError(Threading::pxThread* _thread)
|
||||||
{
|
{
|
||||||
m_thread = _thread;
|
m_thread = _thread;
|
||||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit BaseThreadError(Threading::pxThread &_thread)
|
explicit BaseThreadError(Threading::pxThread& _thread)
|
||||||
{
|
{
|
||||||
m_thread = &_thread;
|
m_thread = &_thread;
|
||||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
virtual wxString FormatDisplayMessage() const;
|
virtual wxString FormatDisplayMessage() const;
|
||||||
|
|
||||||
Threading::pxThread &Thread();
|
Threading::pxThread& Thread();
|
||||||
const Threading::pxThread &Thread() const;
|
const Threading::pxThread& Thread() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadCreationError : public BaseThreadError
|
class ThreadCreationError : public BaseThreadError
|
||||||
{
|
{
|
||||||
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
|
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ThreadCreationError(Threading::pxThread *_thread)
|
explicit ThreadCreationError(Threading::pxThread* _thread)
|
||||||
{
|
{
|
||||||
m_thread = _thread;
|
m_thread = _thread;
|
||||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit ThreadCreationError(Threading::pxThread &_thread)
|
explicit ThreadCreationError(Threading::pxThread& _thread)
|
||||||
{
|
{
|
||||||
m_thread = &_thread;
|
m_thread = &_thread;
|
||||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Exception
|
||||||
|
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Platform Specific External APIs
|
// Platform Specific External APIs
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// The following set of documented functions have Linux/Win32 specific implementations,
|
// The following set of documented functions have Linux/Win32 specific implementations,
|
||||||
// which are found in WinThreads.cpp and LnxThreads.cpp
|
// which are found in WinThreads.cpp and LnxThreads.cpp
|
||||||
|
|
||||||
// Releases a timeslice to other threads.
|
// Releases a timeslice to other threads.
|
||||||
extern void Timeslice();
|
extern void Timeslice();
|
||||||
|
|
||||||
// For use in spin/wait loops.
|
// For use in spin/wait loops.
|
||||||
extern void SpinWait();
|
extern void SpinWait();
|
||||||
|
|
||||||
// Optional implementation to enable hires thread/process scheduler for the operating system.
|
// Optional implementation to enable hires thread/process scheduler for the operating system.
|
||||||
// Needed by Windows, but might not be relevant to other platforms.
|
// Needed by Windows, but might not be relevant to other platforms.
|
||||||
extern void EnableHiresScheduler();
|
extern void EnableHiresScheduler();
|
||||||
extern void DisableHiresScheduler();
|
extern void DisableHiresScheduler();
|
||||||
|
|
||||||
// sleeps the current thread for the given number of milliseconds.
|
// sleeps the current thread for the given number of milliseconds.
|
||||||
extern void Sleep(int ms);
|
extern void Sleep(int ms);
|
||||||
|
|
||||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||||
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
|
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
|
||||||
|
@ -196,230 +196,230 @@ extern void Sleep(int ms);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// NonblockingMutex
|
// NonblockingMutex
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
|
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
|
||||||
// trylock(), but without any of the extra overhead needed to set up a structure capable
|
// trylock(), but without any of the extra overhead needed to set up a structure capable
|
||||||
// of blocking waits. It basically optimizes to a single InterlockedExchange.
|
// of blocking waits. It basically optimizes to a single InterlockedExchange.
|
||||||
//
|
//
|
||||||
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
|
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
|
||||||
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
|
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
|
||||||
// it later.
|
// it later.
|
||||||
//
|
//
|
||||||
class NonblockingMutex
|
class NonblockingMutex
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::atomic_flag val;
|
std::atomic_flag val;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NonblockingMutex() { val.clear(); }
|
NonblockingMutex() { val.clear(); }
|
||||||
virtual ~NonblockingMutex() = default;
|
virtual ~NonblockingMutex() = default;
|
||||||
|
|
||||||
bool TryAcquire() noexcept
|
bool TryAcquire() noexcept
|
||||||
{
|
{
|
||||||
return !val.test_and_set();
|
return !val.test_and_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
|
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
|
||||||
bool IsLocked()
|
bool IsLocked()
|
||||||
{
|
{
|
||||||
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
|
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Release()
|
void Release()
|
||||||
{
|
{
|
||||||
val.clear();
|
val.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Semaphore
|
class Semaphore
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
semaphore_t m_sema;
|
semaphore_t m_sema;
|
||||||
int m_counter;
|
int m_counter;
|
||||||
#else
|
#else
|
||||||
sem_t m_sema;
|
sem_t m_sema;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Semaphore();
|
Semaphore();
|
||||||
virtual ~Semaphore();
|
virtual ~Semaphore();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void Post();
|
void Post();
|
||||||
void Post(int multiple);
|
void Post(int multiple);
|
||||||
|
|
||||||
void WaitWithoutYield();
|
void WaitWithoutYield();
|
||||||
bool WaitWithoutYield(const wxTimeSpan &timeout);
|
bool WaitWithoutYield(const wxTimeSpan& timeout);
|
||||||
void WaitNoCancel();
|
void WaitNoCancel();
|
||||||
void WaitNoCancel(const wxTimeSpan &timeout);
|
void WaitNoCancel(const wxTimeSpan& timeout);
|
||||||
int Count();
|
int Count();
|
||||||
|
|
||||||
void Wait();
|
void Wait();
|
||||||
bool Wait(const wxTimeSpan &timeout);
|
bool Wait(const wxTimeSpan& timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Mutex
|
class Mutex
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
pthread_mutex_t m_mutex;
|
pthread_mutex_t m_mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mutex();
|
Mutex();
|
||||||
virtual ~Mutex();
|
virtual ~Mutex();
|
||||||
virtual bool IsRecursive() const { return false; }
|
virtual bool IsRecursive() const { return false; }
|
||||||
|
|
||||||
void Recreate();
|
void Recreate();
|
||||||
bool RecreateIfLocked();
|
bool RecreateIfLocked();
|
||||||
void Detach();
|
void Detach();
|
||||||
|
|
||||||
void Acquire();
|
void Acquire();
|
||||||
bool Acquire(const wxTimeSpan &timeout);
|
bool Acquire(const wxTimeSpan& timeout);
|
||||||
bool TryAcquire();
|
bool TryAcquire();
|
||||||
void Release();
|
void Release();
|
||||||
|
|
||||||
void AcquireWithoutYield();
|
void AcquireWithoutYield();
|
||||||
bool AcquireWithoutYield(const wxTimeSpan &timeout);
|
bool AcquireWithoutYield(const wxTimeSpan& timeout);
|
||||||
|
|
||||||
void Wait();
|
void Wait();
|
||||||
bool Wait(const wxTimeSpan &timeout);
|
bool Wait(const wxTimeSpan& timeout);
|
||||||
void WaitWithoutYield();
|
void WaitWithoutYield();
|
||||||
bool WaitWithoutYield(const wxTimeSpan &timeout);
|
bool WaitWithoutYield(const wxTimeSpan& timeout);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// empty constructor used by MutexLockRecursive
|
// empty constructor used by MutexLockRecursive
|
||||||
Mutex(bool) {}
|
Mutex(bool) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MutexRecursive : public Mutex
|
class MutexRecursive : public Mutex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MutexRecursive();
|
MutexRecursive();
|
||||||
virtual ~MutexRecursive();
|
virtual ~MutexRecursive();
|
||||||
virtual bool IsRecursive() const { return true; }
|
virtual bool IsRecursive() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ScopedLock
|
// ScopedLock
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Helper class for using Mutexes. Using this class provides an exception-safe (and
|
// Helper class for using Mutexes. Using this class provides an exception-safe (and
|
||||||
// generally clean) method of locking code inside a function or conditional block. The lock
|
// generally clean) method of locking code inside a function or conditional block. The lock
|
||||||
// will be automatically released on any return or exit from the function.
|
// will be automatically released on any return or exit from the function.
|
||||||
//
|
//
|
||||||
// Const qualification note:
|
// Const qualification note:
|
||||||
// ScopedLock takes const instances of the mutex, even though the mutex is modified
|
// ScopedLock takes const instances of the mutex, even though the mutex is modified
|
||||||
// by locking and unlocking. Two rationales:
|
// by locking and unlocking. Two rationales:
|
||||||
//
|
//
|
||||||
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
|
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
|
||||||
// this class needs a const hack to allow those accessors to be const (which is typically
|
// this class needs a const hack to allow those accessors to be const (which is typically
|
||||||
// *very* important).
|
// *very* important).
|
||||||
//
|
//
|
||||||
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
|
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
|
||||||
// scope exits, by any means. Only via manual calls to Release or Acquire does that
|
// scope exits, by any means. Only via manual calls to Release or Acquire does that
|
||||||
// change, and typically those are only used in very special circumstances of their own.
|
// change, and typically those are only used in very special circumstances of their own.
|
||||||
//
|
//
|
||||||
class ScopedLock
|
class ScopedLock
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ScopedLock);
|
DeclareNoncopyableObject(ScopedLock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mutex *m_lock;
|
Mutex* m_lock;
|
||||||
bool m_IsLocked;
|
bool m_IsLocked;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ScopedLock();
|
virtual ~ScopedLock();
|
||||||
explicit ScopedLock(const Mutex *locker = NULL);
|
explicit ScopedLock(const Mutex* locker = NULL);
|
||||||
explicit ScopedLock(const Mutex &locker);
|
explicit ScopedLock(const Mutex& locker);
|
||||||
void AssignAndLock(const Mutex &locker);
|
void AssignAndLock(const Mutex& locker);
|
||||||
void AssignAndLock(const Mutex *locker);
|
void AssignAndLock(const Mutex* locker);
|
||||||
|
|
||||||
void Assign(const Mutex &locker);
|
void Assign(const Mutex& locker);
|
||||||
void Assign(const Mutex *locker);
|
void Assign(const Mutex* locker);
|
||||||
|
|
||||||
void Release();
|
void Release();
|
||||||
void Acquire();
|
void Acquire();
|
||||||
|
|
||||||
bool IsLocked() const { return m_IsLocked; }
|
bool IsLocked() const { return m_IsLocked; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Special constructor used by ScopedTryLock
|
// Special constructor used by ScopedTryLock
|
||||||
ScopedLock(const Mutex &locker, bool isTryLock);
|
ScopedLock(const Mutex& locker, bool isTryLock);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScopedTryLock : public ScopedLock
|
class ScopedTryLock : public ScopedLock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopedTryLock(const Mutex &locker)
|
ScopedTryLock(const Mutex& locker)
|
||||||
: ScopedLock(locker, true)
|
: ScopedLock(locker, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~ScopedTryLock() = default;
|
virtual ~ScopedTryLock() = default;
|
||||||
bool Failed() const { return !m_IsLocked; }
|
bool Failed() const { return !m_IsLocked; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ScopedNonblockingLock
|
// ScopedNonblockingLock
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
|
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
|
||||||
//
|
//
|
||||||
class ScopedNonblockingLock
|
class ScopedNonblockingLock
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(ScopedNonblockingLock);
|
DeclareNoncopyableObject(ScopedNonblockingLock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NonblockingMutex &m_lock;
|
NonblockingMutex& m_lock;
|
||||||
bool m_IsLocked;
|
bool m_IsLocked;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedNonblockingLock(NonblockingMutex &locker)
|
ScopedNonblockingLock(NonblockingMutex& locker)
|
||||||
: m_lock(locker)
|
: m_lock(locker)
|
||||||
, m_IsLocked(m_lock.TryAcquire())
|
, m_IsLocked(m_lock.TryAcquire())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ScopedNonblockingLock()
|
virtual ~ScopedNonblockingLock()
|
||||||
{
|
{
|
||||||
if (m_IsLocked)
|
if (m_IsLocked)
|
||||||
m_lock.Release();
|
m_lock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Failed() const { return !m_IsLocked; }
|
bool Failed() const { return !m_IsLocked; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ScopedLockBool
|
// ScopedLockBool
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
|
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
|
||||||
// Note that the isLockedBool should only be used as an indicator for the locked status,
|
// Note that the isLockedBool should only be used as an indicator for the locked status,
|
||||||
// and not actually depended on for thread synchronization...
|
// and not actually depended on for thread synchronization...
|
||||||
|
|
||||||
struct ScopedLockBool
|
struct ScopedLockBool
|
||||||
{
|
{
|
||||||
ScopedLock m_lock;
|
ScopedLock m_lock;
|
||||||
std::atomic<bool> &m_bool;
|
std::atomic<bool>& m_bool;
|
||||||
|
|
||||||
ScopedLockBool(Mutex &mutexToLock, std::atomic<bool> &isLockedBool)
|
ScopedLockBool(Mutex& mutexToLock, std::atomic<bool>& isLockedBool)
|
||||||
: m_lock(mutexToLock)
|
: m_lock(mutexToLock)
|
||||||
, m_bool(isLockedBool)
|
, m_bool(isLockedBool)
|
||||||
{
|
{
|
||||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
virtual ~ScopedLockBool()
|
virtual ~ScopedLockBool()
|
||||||
{
|
{
|
||||||
m_bool.store(false, std::memory_order_relaxed);
|
m_bool.store(false, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
void Acquire()
|
void Acquire()
|
||||||
{
|
{
|
||||||
m_lock.Acquire();
|
m_lock.Acquire();
|
||||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
void Release()
|
void Release()
|
||||||
{
|
{
|
||||||
m_bool.store(false, std::memory_order_relaxed);
|
m_bool.store(false, std::memory_order_relaxed);
|
||||||
m_lock.Release();
|
m_lock.Release();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -25,60 +25,60 @@ wxDEFINE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxIMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers);
|
wxIMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers);
|
||||||
|
|
||||||
Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString &title, const wxString &heading)
|
Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString& title, const wxString& heading)
|
||||||
: wxDialogWithHelpers(NULL, _("Waiting for tasks..."))
|
: wxDialogWithHelpers(NULL, _("Waiting for tasks..."))
|
||||||
//, m_Timer(this)
|
//, m_Timer(this)
|
||||||
{
|
{
|
||||||
SetMinWidth(300);
|
SetMinWidth(300);
|
||||||
|
|
||||||
//m_sem = sem;
|
//m_sem = sem;
|
||||||
//m_mutex = mutex;
|
//m_mutex = mutex;
|
||||||
|
|
||||||
wxString m_title(title);
|
wxString m_title(title);
|
||||||
wxString m_heading(heading);
|
wxString m_heading(heading);
|
||||||
|
|
||||||
if (m_title.IsEmpty())
|
if (m_title.IsEmpty())
|
||||||
m_title = _("Waiting for task...");
|
m_title = _("Waiting for task...");
|
||||||
if (m_heading.IsEmpty())
|
if (m_heading.IsEmpty())
|
||||||
m_heading = m_title;
|
m_heading = m_title;
|
||||||
|
|
||||||
Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this);
|
Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this);
|
||||||
|
|
||||||
*this += 12;
|
*this += 12;
|
||||||
*this += Heading(m_heading).Unwrapped() | StdExpand();
|
*this += Heading(m_heading).Unwrapped() | StdExpand();
|
||||||
*this += 12;
|
*this += 12;
|
||||||
|
|
||||||
// TODO : Implement a cancel button. Not quite sure the best way to do
|
// TODO : Implement a cancel button. Not quite sure the best way to do
|
||||||
// that, since it requires a thread or event handler context, or something.
|
// that, since it requires a thread or event handler context, or something.
|
||||||
|
|
||||||
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
||||||
//applyDlg += 6;
|
//applyDlg += 6;
|
||||||
|
|
||||||
//Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId());
|
//Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId());
|
||||||
//m_Timer.Start( 200 );
|
//m_Timer.Start( 200 );
|
||||||
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent &evt)
|
void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
|
|
||||||
// Note: we don't throw exceptions from the pending task here.
|
// Note: we don't throw exceptions from the pending task here.
|
||||||
// Instead we wait until we exit the modal loop below -- this gives
|
// Instead we wait until we exit the modal loop below -- this gives
|
||||||
// the caller a chance to handle the exception themselves, and if
|
// the caller a chance to handle the exception themselves, and if
|
||||||
// not the exception will still fall back on the standard app-level
|
// not the exception will still fall back on the standard app-level
|
||||||
// exception handler.
|
// exception handler.
|
||||||
|
|
||||||
// (this also avoids any sticky business with the modal dialog not getting
|
// (this also avoids any sticky business with the modal dialog not getting
|
||||||
// closed out right due to stack unwinding skipping dialog closure crap)
|
// closed out right due to stack unwinding skipping dialog closure crap)
|
||||||
|
|
||||||
m_sync.WaitForResult_NoExceptions();
|
m_sync.WaitForResult_NoExceptions();
|
||||||
EndModal(wxID_OK);
|
EndModal(wxID_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Threading::WaitForTaskDialog::ShowModal()
|
int Threading::WaitForTaskDialog::ShowModal()
|
||||||
{
|
{
|
||||||
int result = _parent::ShowModal();
|
int result = _parent::ShowModal();
|
||||||
m_sync.RethrowException();
|
m_sync.RethrowException();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,31 +22,31 @@ wxDECLARE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// WaitForTaskDialog
|
// WaitForTaskDialog
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This dialog is displayed whenever the main thread is recursively waiting on multiple
|
// This dialog is displayed whenever the main thread is recursively waiting on multiple
|
||||||
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
|
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
|
||||||
// but it *does* support opening a modal dialog, which disables the interface (preventing
|
// but it *does* support opening a modal dialog, which disables the interface (preventing
|
||||||
// the user from starting additional actions), and processes messages (allowing the system
|
// the user from starting additional actions), and processes messages (allowing the system
|
||||||
// to continue to manage threads and process logging).
|
// to continue to manage threads and process logging).
|
||||||
//
|
//
|
||||||
class WaitForTaskDialog : public wxDialogWithHelpers
|
class WaitForTaskDialog : public wxDialogWithHelpers
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
|
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
|
||||||
|
|
||||||
typedef wxDialogWithHelpers _parent;
|
typedef wxDialogWithHelpers _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SynchronousActionState m_sync;
|
SynchronousActionState m_sync;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WaitForTaskDialog(const wxString &title = wxEmptyString, const wxString &heading = wxEmptyString);
|
WaitForTaskDialog(const wxString& title = wxEmptyString, const wxString& heading = wxEmptyString);
|
||||||
virtual ~WaitForTaskDialog() = default;
|
virtual ~WaitForTaskDialog() = default;
|
||||||
virtual int ShowModal();
|
virtual int ShowModal();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnTaskComplete(wxCommandEvent &evt);
|
void OnTaskComplete(wxCommandEvent& evt);
|
||||||
//void OnTimer( wxTimerEvent& evt );
|
//void OnTimer( wxTimerEvent& evt );
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
extern const wxTimeSpan def_yieldgui_interval;
|
extern const wxTimeSpan def_yieldgui_interval;
|
||||||
|
|
||||||
extern bool _WaitGui_RecursionGuard(const wxChar *name);
|
extern bool _WaitGui_RecursionGuard(const wxChar* name);
|
||||||
|
|
||||||
extern void YieldToMain();
|
extern void YieldToMain();
|
||||||
extern bool AllowDeletions();
|
extern bool AllowDeletions();
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -29,20 +29,20 @@
|
||||||
//
|
//
|
||||||
struct TraceLogDescriptor
|
struct TraceLogDescriptor
|
||||||
{
|
{
|
||||||
// short name, alphanumerics only: used for saving/loading options.
|
// short name, alphanumerics only: used for saving/loading options.
|
||||||
const wxChar *ShortName;
|
const wxChar* ShortName;
|
||||||
|
|
||||||
// Standard UI name for this log source. Used in menus, options dialogs.
|
// Standard UI name for this log source. Used in menus, options dialogs.
|
||||||
const wxChar *Name;
|
const wxChar* Name;
|
||||||
|
|
||||||
// Length description for use as a tooltip or menu item description.
|
// Length description for use as a tooltip or menu item description.
|
||||||
const wxChar *Description;
|
const wxChar* Description;
|
||||||
|
|
||||||
wxString GetShortName() const
|
wxString GetShortName() const
|
||||||
{
|
{
|
||||||
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
|
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
|
||||||
return ShortName ? ShortName : Name;
|
return ShortName ? ShortName : Name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -66,51 +66,51 @@ struct TraceLogDescriptor
|
||||||
class BaseTraceLogSource
|
class BaseTraceLogSource
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const TraceLogDescriptor *m_Descriptor;
|
const TraceLogDescriptor* m_Descriptor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Indicates if the user has enabled this specific log. This boolean only represents
|
// Indicates if the user has enabled this specific log. This boolean only represents
|
||||||
// the configured status of this log, and does *NOT* actually mean the log is active
|
// the configured status of this log, and does *NOT* actually mean the log is active
|
||||||
// even when TRUE. Because many tracelogs have master enablers that act on a group
|
// even when TRUE. Because many tracelogs have master enablers that act on a group
|
||||||
// of logs, logging checks should always use IsActive() instead to determine if a log
|
// of logs, logging checks should always use IsActive() instead to determine if a log
|
||||||
// should be processed or not.
|
// should be processed or not.
|
||||||
bool Enabled;
|
bool Enabled;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BaseTraceLogSource()
|
BaseTraceLogSource()
|
||||||
: m_Descriptor(NULL)
|
: m_Descriptor(NULL)
|
||||||
, Enabled(false)
|
, Enabled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
|
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
|
||||||
|
|
||||||
BaseTraceLogSource(const TraceLogDescriptor *desc)
|
BaseTraceLogSource(const TraceLogDescriptor* desc)
|
||||||
{
|
{
|
||||||
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
|
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
|
||||||
Enabled = false;
|
Enabled = false;
|
||||||
m_Descriptor = desc;
|
m_Descriptor = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
|
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
|
||||||
// (use periods in favor of colons, since they do not require escape characters when
|
// (use periods in favor of colons, since they do not require escape characters when
|
||||||
// written to ini/config files).
|
// written to ini/config files).
|
||||||
virtual wxString GetCategory() const { return wxEmptyString; }
|
virtual wxString GetCategory() const { return wxEmptyString; }
|
||||||
|
|
||||||
// This method should be used to determine if a log should be generated or not.
|
// This method should be used to determine if a log should be generated or not.
|
||||||
// See the class overview comments for details on how and why this method should
|
// See the class overview comments for details on how and why this method should
|
||||||
// be used.
|
// be used.
|
||||||
virtual bool IsActive() const { return Enabled; }
|
virtual bool IsActive() const { return Enabled; }
|
||||||
|
|
||||||
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
|
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
|
||||||
virtual const wxChar *GetName() const { return m_Descriptor->Name; }
|
virtual const wxChar* GetName() const { return m_Descriptor->Name; }
|
||||||
virtual const wxChar *GetDescription() const
|
virtual const wxChar* GetDescription() const
|
||||||
{
|
{
|
||||||
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
|
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool HasDescription() const { return m_Descriptor->Description != NULL; }
|
virtual bool HasDescription() const { return m_Descriptor->Description != NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -122,32 +122,32 @@ public:
|
||||||
class TextFileTraceLog : public BaseTraceLogSource
|
class TextFileTraceLog : public BaseTraceLogSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextFileTraceLog(const TraceLogDescriptor *desc)
|
TextFileTraceLog(const TraceLogDescriptor* desc)
|
||||||
: BaseTraceLogSource(desc)
|
: BaseTraceLogSource(desc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Write(const char *fmt, ...) const
|
bool Write(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteV(const char *fmt, va_list list) const
|
bool WriteV(const char* fmt, va_list list) const
|
||||||
{
|
{
|
||||||
FastFormatAscii ascii;
|
FastFormatAscii ascii;
|
||||||
ApplyPrefix(ascii);
|
ApplyPrefix(ascii);
|
||||||
ascii.WriteV(fmt, list);
|
ascii.WriteV(fmt, list);
|
||||||
DoWrite(ascii);
|
DoWrite(ascii);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void ApplyPrefix(FastFormatAscii &ascii) const {}
|
virtual void ApplyPrefix(FastFormatAscii& ascii) const {}
|
||||||
virtual void DoWrite(const char *fmt) const = 0;
|
virtual void DoWrite(const char* fmt) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -159,130 +159,130 @@ public:
|
||||||
class ConsoleLogSource : public BaseTraceLogSource
|
class ConsoleLogSource : public BaseTraceLogSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConsoleColors DefaultColor;
|
ConsoleColors DefaultColor;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ConsoleLogSource()
|
ConsoleLogSource()
|
||||||
: DefaultColor(Color_Gray)
|
: DefaultColor(Color_Gray)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
|
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
|
||||||
|
|
||||||
ConsoleLogSource(const TraceLogDescriptor *desc, ConsoleColors defaultColor = Color_Gray)
|
ConsoleLogSource(const TraceLogDescriptor* desc, ConsoleColors defaultColor = Color_Gray)
|
||||||
: BaseTraceLogSource(desc)
|
: BaseTraceLogSource(desc)
|
||||||
{
|
{
|
||||||
DefaultColor = defaultColor;
|
DefaultColor = defaultColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes to the console using the source's default color. Note that the source's default
|
// Writes to the console using the source's default color. Note that the source's default
|
||||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||||
// console's default color is Color_Default.
|
// console's default color is Color_Default.
|
||||||
bool Write(const char *fmt, ...) const
|
bool Write(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Write(const wxChar *fmt, ...) const
|
bool Write(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt, list);
|
WriteV(fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Write(const wxString fmt, ...) const
|
bool Write(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(fmt.wx_str(), list);
|
WriteV(fmt.wx_str(), list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes to the console using the specified color. This overrides the default color setting
|
// Writes to the console using the specified color. This overrides the default color setting
|
||||||
// for this log.
|
// for this log.
|
||||||
bool Write(ConsoleColors color, const char *fmt, ...) const
|
bool Write(ConsoleColors color, const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(color, fmt, list);
|
WriteV(color, fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Write(ConsoleColors color, const wxChar *fmt, ...) const
|
bool Write(ConsoleColors color, const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(color, fmt, list);
|
WriteV(color, fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes to the console using bold yellow text -- overrides the log source's default
|
// Writes to the console using bold yellow text -- overrides the log source's default
|
||||||
// color settings.
|
// color settings.
|
||||||
bool Warn(const wxChar *fmt, ...) const
|
bool Warn(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(Color_StrongYellow, fmt, list);
|
WriteV(Color_StrongYellow, fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Warn(const wxString fmt, ...) const
|
bool Warn(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(Color_StrongYellow, fmt.wx_str(), list);
|
WriteV(Color_StrongYellow, fmt.wx_str(), list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes to the console using bold red text -- overrides the log source's default
|
// Writes to the console using bold red text -- overrides the log source's default
|
||||||
// color settings.
|
// color settings.
|
||||||
bool Error(const wxChar *fmt, ...) const
|
bool Error(const wxChar* fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(Color_StrongRed, fmt, list);
|
WriteV(Color_StrongRed, fmt, list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Error(const wxString fmt, ...) const
|
bool Error(const wxString fmt, ...) const
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, fmt);
|
va_start(list, fmt);
|
||||||
WriteV(Color_StrongRed, fmt.wx_str(), list);
|
WriteV(Color_StrongRed, fmt.wx_str(), list);
|
||||||
va_end(list);
|
va_end(list);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteV(const char *fmt, va_list list) const;
|
bool WriteV(const char* fmt, va_list list) const;
|
||||||
bool WriteV(const wxChar *fmt, va_list list) const;
|
bool WriteV(const wxChar* fmt, va_list list) const;
|
||||||
|
|
||||||
bool WriteV(ConsoleColors color, const char *fmt, va_list list) const;
|
bool WriteV(ConsoleColors color, const char* fmt, va_list list) const;
|
||||||
bool WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const;
|
bool WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const;
|
||||||
|
|
||||||
virtual void DoWrite(const wxChar *msg) const
|
virtual void DoWrite(const wxChar* msg) const
|
||||||
{
|
{
|
||||||
Console.DoWriteLn(msg);
|
Console.DoWriteLn(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,18 +22,19 @@
|
||||||
|
|
||||||
template class EventSource<IEventListener_PageFault>;
|
template class EventSource<IEventListener_PageFault>;
|
||||||
|
|
||||||
SrcType_PageFault *Source_PageFault = NULL;
|
SrcType_PageFault* Source_PageFault = NULL;
|
||||||
Threading::Mutex PageFault_Mutex;
|
Threading::Mutex PageFault_Mutex;
|
||||||
|
|
||||||
void pxInstallSignalHandler()
|
void pxInstallSignalHandler()
|
||||||
{
|
{
|
||||||
if (!Source_PageFault) {
|
if (!Source_PageFault)
|
||||||
Source_PageFault = new SrcType_PageFault();
|
{
|
||||||
}
|
Source_PageFault = new SrcType_PageFault();
|
||||||
|
}
|
||||||
|
|
||||||
_platform_InstallSignalHandler();
|
_platform_InstallSignalHandler();
|
||||||
|
|
||||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -41,200 +42,221 @@ void pxInstallSignalHandler()
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
EventListener_PageFault::EventListener_PageFault()
|
EventListener_PageFault::EventListener_PageFault()
|
||||||
{
|
{
|
||||||
pxAssert(Source_PageFault);
|
pxAssert(Source_PageFault);
|
||||||
Source_PageFault->Add(*this);
|
Source_PageFault->Add(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListener_PageFault::~EventListener_PageFault()
|
EventListener_PageFault::~EventListener_PageFault()
|
||||||
{
|
{
|
||||||
if (Source_PageFault)
|
if (Source_PageFault)
|
||||||
Source_PageFault->Remove(*this);
|
Source_PageFault->Remove(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrcType_PageFault::Dispatch(const PageFaultInfo ¶ms)
|
void SrcType_PageFault::Dispatch(const PageFaultInfo& params)
|
||||||
{
|
{
|
||||||
m_handled = false;
|
m_handled = false;
|
||||||
_parent::Dispatch(params);
|
_parent::Dispatch(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt)
|
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt)
|
||||||
{
|
{
|
||||||
do {
|
do
|
||||||
(*iter)->DispatchEvent(evt, m_handled);
|
{
|
||||||
} while ((++iter != iend) && !m_handled);
|
(*iter)->DispatchEvent(evt, m_handled);
|
||||||
|
} while ((++iter != iend) && !m_handled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t pageAlign(size_t size)
|
static size_t pageAlign(size_t size)
|
||||||
{
|
{
|
||||||
return (size + __pagesize - 1) / __pagesize * __pagesize;
|
return (size + __pagesize - 1) / __pagesize * __pagesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// VirtualMemoryManager (implementations)
|
// VirtualMemoryManager (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
VirtualMemoryManager::VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
VirtualMemoryManager::VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
||||||
: m_name(name), m_baseptr(0), m_pageuse(nullptr), m_pages_reserved(0)
|
: m_name(name)
|
||||||
|
, m_baseptr(0)
|
||||||
|
, m_pageuse(nullptr)
|
||||||
|
, m_pages_reserved(0)
|
||||||
{
|
{
|
||||||
if (!size) return;
|
if (!size)
|
||||||
|
return;
|
||||||
|
|
||||||
uptr reserved_bytes = pageAlign(size);
|
uptr reserved_bytes = pageAlign(size);
|
||||||
m_pages_reserved = reserved_bytes / __pagesize;
|
m_pages_reserved = reserved_bytes / __pagesize;
|
||||||
|
|
||||||
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
||||||
|
|
||||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) {
|
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||||
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
{
|
||||||
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
||||||
|
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
||||||
|
|
||||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||||
|
|
||||||
if (base) {
|
if (base)
|
||||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
{
|
||||||
// boundschecking criteria below.
|
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||||
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
// boundschecking criteria below.
|
||||||
}
|
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool fulfillsRequirements = true;
|
bool fulfillsRequirements = true;
|
||||||
if (strict && m_baseptr != base)
|
if (strict && m_baseptr != base)
|
||||||
fulfillsRequirements = false;
|
fulfillsRequirements = false;
|
||||||
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
||||||
fulfillsRequirements = false;
|
fulfillsRequirements = false;
|
||||||
if (!fulfillsRequirements) {
|
if (!fulfillsRequirements)
|
||||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
{
|
||||||
}
|
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_baseptr) return;
|
if (!m_baseptr)
|
||||||
|
return;
|
||||||
|
|
||||||
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
||||||
|
|
||||||
FastFormatUnicode mbkb;
|
FastFormatUnicode mbkb;
|
||||||
uint mbytes = reserved_bytes / _1mb;
|
uint mbytes = reserved_bytes / _1mb;
|
||||||
if (mbytes)
|
if (mbytes)
|
||||||
mbkb.Write("[%umb]", mbytes);
|
mbkb.Write("[%umb]", mbytes);
|
||||||
else
|
else
|
||||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||||
|
|
||||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualMemoryManager::~VirtualMemoryManager()
|
VirtualMemoryManager::~VirtualMemoryManager()
|
||||||
{
|
{
|
||||||
if (m_pageuse) delete[] m_pageuse;
|
if (m_pageuse)
|
||||||
if (m_baseptr) HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
delete[] m_pageuse;
|
||||||
|
if (m_baseptr)
|
||||||
|
HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VMMMarkPagesAsInUse(std::atomic<bool> *begin, std::atomic<bool> *end) {
|
static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
|
||||||
for (auto current = begin; current < end; current++) {
|
|
||||||
bool expected = false;
|
|
||||||
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed) {
|
|
||||||
// This was already allocated! Undo the things we've set until this point
|
|
||||||
while (--current >= begin) {
|
|
||||||
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
|
||||||
// In the time we were doing this, someone set one of the things we just set to true back to false
|
|
||||||
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
|
||||||
pxAssert(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
|
||||||
{
|
{
|
||||||
size = pageAlign(size);
|
for (auto current = begin; current < end; current++)
|
||||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
|
{
|
||||||
return nullptr;
|
bool expected = false;
|
||||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
|
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed)
|
||||||
return nullptr;
|
{
|
||||||
if (m_baseptr == 0)
|
// This was already allocated! Undo the things we've set until this point
|
||||||
return nullptr;
|
while (--current >= begin)
|
||||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
{
|
||||||
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize];
|
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||||
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
|
{
|
||||||
return nullptr;
|
// In the time we were doing this, someone set one of the things we just set to true back to false
|
||||||
return (void *)(m_baseptr + offsetLocation);
|
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
||||||
|
pxAssert(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualMemoryManager::Free(void *address, size_t size) const
|
void* VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
||||||
{
|
{
|
||||||
uptr offsetLocation = (uptr)address - m_baseptr;
|
size = pageAlign(size);
|
||||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address")) {
|
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
|
||||||
uptr newLoc = pageAlign(offsetLocation);
|
return nullptr;
|
||||||
size -= (offsetLocation - newLoc);
|
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
|
||||||
offsetLocation = newLoc;
|
return nullptr;
|
||||||
}
|
if (m_baseptr == 0)
|
||||||
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
|
return nullptr;
|
||||||
size -= size % __pagesize;
|
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
|
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||||
return;
|
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
|
||||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
return nullptr;
|
||||||
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize];
|
return (void*)(m_baseptr + offsetLocation);
|
||||||
for (; puStart < puEnd; puStart++) {
|
}
|
||||||
bool expected = true;
|
|
||||||
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
void VirtualMemoryManager::Free(void* address, size_t size) const
|
||||||
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
{
|
||||||
}
|
uptr offsetLocation = (uptr)address - m_baseptr;
|
||||||
}
|
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address"))
|
||||||
|
{
|
||||||
|
uptr newLoc = pageAlign(offsetLocation);
|
||||||
|
size -= (offsetLocation - newLoc);
|
||||||
|
offsetLocation = newLoc;
|
||||||
|
}
|
||||||
|
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
|
||||||
|
size -= size % __pagesize;
|
||||||
|
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
|
||||||
|
return;
|
||||||
|
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||||
|
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||||
|
for (; puStart < puEnd; puStart++)
|
||||||
|
{
|
||||||
|
bool expected = true;
|
||||||
|
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||||
|
{
|
||||||
|
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// VirtualMemoryBumpAllocator (implementations)
|
// VirtualMemoryBumpAllocator (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
||||||
: m_allocator(std::move(allocator)), m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size)), m_endptr(m_baseptr + size)
|
: m_allocator(std::move(allocator))
|
||||||
|
, m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size))
|
||||||
|
, m_endptr(m_baseptr + size)
|
||||||
{
|
{
|
||||||
if (m_baseptr.load() == 0)
|
if (m_baseptr.load() == 0)
|
||||||
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
void *VirtualMemoryBumpAllocator::Alloc(size_t size)
|
void* VirtualMemoryBumpAllocator::Alloc(size_t size)
|
||||||
{
|
{
|
||||||
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
|
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
size_t reservedSize = pageAlign(size);
|
size_t reservedSize = pageAlign(size);
|
||||||
|
|
||||||
uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
|
uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
|
||||||
|
|
||||||
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
|
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return (void *)out;
|
return (void*)out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// VirtualMemoryReserve (implementations)
|
// VirtualMemoryReserve (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
VirtualMemoryReserve::VirtualMemoryReserve(const wxString &name, size_t size)
|
VirtualMemoryReserve::VirtualMemoryReserve(const wxString& name, size_t size)
|
||||||
: m_name(name)
|
: m_name(name)
|
||||||
{
|
{
|
||||||
m_defsize = size;
|
m_defsize = size;
|
||||||
|
|
||||||
m_allocator = nullptr;
|
m_allocator = nullptr;
|
||||||
m_pages_commited = 0;
|
m_pages_commited = 0;
|
||||||
m_pages_reserved = 0;
|
m_pages_reserved = 0;
|
||||||
m_baseptr = nullptr;
|
m_baseptr = nullptr;
|
||||||
m_prot_mode = PageAccess_None();
|
m_prot_mode = PageAccess_None();
|
||||||
m_allow_writes = true;
|
m_allow_writes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualMemoryReserve &VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode &mode)
|
VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
m_prot_mode = mode;
|
m_prot_mode = mode;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
|
size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
|
||||||
{
|
{
|
||||||
if (!requestedSize)
|
if (!requestedSize)
|
||||||
return pageAlign(m_defsize);
|
return pageAlign(m_defsize);
|
||||||
return pageAlign(requestedSize);
|
return pageAlign(requestedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notes:
|
// Notes:
|
||||||
|
@ -245,84 +267,85 @@ size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
|
||||||
// baseptr - the new base pointer that's about to be assigned
|
// baseptr - the new base pointer that's about to be assigned
|
||||||
// size - size of the region pointed to by baseptr
|
// size - size of the region pointed to by baseptr
|
||||||
//
|
//
|
||||||
void *VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void * baseptr, size_t size)
|
void* VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size)
|
||||||
{
|
{
|
||||||
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
|
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
|
||||||
return m_baseptr;
|
return m_baseptr;
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
m_allocator = std::move(allocator);
|
m_allocator = std::move(allocator);
|
||||||
|
|
||||||
m_baseptr = baseptr;
|
m_baseptr = baseptr;
|
||||||
|
|
||||||
uptr reserved_bytes = pageAlign(size);
|
uptr reserved_bytes = pageAlign(size);
|
||||||
m_pages_reserved = reserved_bytes / __pagesize;
|
m_pages_reserved = reserved_bytes / __pagesize;
|
||||||
|
|
||||||
if (!m_baseptr)
|
if (!m_baseptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
FastFormatUnicode mbkb;
|
FastFormatUnicode mbkb;
|
||||||
uint mbytes = reserved_bytes / _1mb;
|
uint mbytes = reserved_bytes / _1mb;
|
||||||
if (mbytes)
|
if (mbytes)
|
||||||
mbkb.Write("[%umb]", mbytes);
|
mbkb.Write("[%umb]", mbytes);
|
||||||
else
|
else
|
||||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||||
|
|
||||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||||
|
|
||||||
return m_baseptr;
|
return m_baseptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode &newmode)
|
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode& newmode)
|
||||||
{
|
{
|
||||||
if (!m_pages_commited)
|
if (!m_pages_commited)
|
||||||
return;
|
return;
|
||||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
|
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears all committed blocks, restoring the allocation to a reserve only.
|
// Clears all committed blocks, restoring the allocation to a reserve only.
|
||||||
void VirtualMemoryReserve::Reset()
|
void VirtualMemoryReserve::Reset()
|
||||||
{
|
{
|
||||||
if (!m_pages_commited)
|
if (!m_pages_commited)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ReprotectCommittedBlocks(PageAccess_None());
|
ReprotectCommittedBlocks(PageAccess_None());
|
||||||
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
|
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
|
||||||
m_pages_commited = 0;
|
m_pages_commited = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualMemoryReserve::Release()
|
void VirtualMemoryReserve::Release()
|
||||||
{
|
{
|
||||||
if (!m_baseptr) return;
|
if (!m_baseptr)
|
||||||
Reset();
|
return;
|
||||||
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
Reset();
|
||||||
m_baseptr = nullptr;
|
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
||||||
|
m_baseptr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualMemoryReserve::Commit()
|
bool VirtualMemoryReserve::Commit()
|
||||||
{
|
{
|
||||||
if (!m_pages_reserved)
|
if (!m_pages_reserved)
|
||||||
return false;
|
return false;
|
||||||
if (!pxAssert(!m_pages_commited))
|
if (!pxAssert(!m_pages_commited))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
m_pages_commited = m_pages_reserved;
|
m_pages_commited = m_pages_reserved;
|
||||||
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
|
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualMemoryReserve::AllowModification()
|
void VirtualMemoryReserve::AllowModification()
|
||||||
{
|
{
|
||||||
m_allow_writes = true;
|
m_allow_writes = true;
|
||||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
|
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualMemoryReserve::ForbidModification()
|
void VirtualMemoryReserve::ForbidModification()
|
||||||
{
|
{
|
||||||
m_allow_writes = false;
|
m_allow_writes = false;
|
||||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
|
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -337,39 +360,43 @@ void VirtualMemoryReserve::ForbidModification()
|
||||||
// newsize - new size of the reserved buffer, in bytes.
|
// newsize - new size of the reserved buffer, in bytes.
|
||||||
bool VirtualMemoryReserve::TryResize(uint newsize)
|
bool VirtualMemoryReserve::TryResize(uint newsize)
|
||||||
{
|
{
|
||||||
uint newPages = pageAlign(newsize) / __pagesize;
|
uint newPages = pageAlign(newsize) / __pagesize;
|
||||||
|
|
||||||
if (newPages > m_pages_reserved) {
|
if (newPages > m_pages_reserved)
|
||||||
uint toReservePages = newPages - m_pages_reserved;
|
{
|
||||||
uint toReserveBytes = toReservePages * __pagesize;
|
uint toReservePages = newPages - m_pages_reserved;
|
||||||
|
uint toReserveBytes = toReservePages * __pagesize;
|
||||||
|
|
||||||
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
||||||
|
|
||||||
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes)) {
|
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes))
|
||||||
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
{
|
||||||
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
||||||
return false;
|
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||||
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
||||||
} else if (newPages < m_pages_reserved) {
|
}
|
||||||
if (m_pages_commited > newsize)
|
else if (newPages < m_pages_reserved)
|
||||||
return false;
|
{
|
||||||
|
if (m_pages_commited > newsize)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint toRemovePages = m_pages_reserved - newPages;
|
uint toRemovePages = m_pages_reserved - newPages;
|
||||||
uint toRemoveBytes = toRemovePages * __pagesize;
|
uint toRemoveBytes = toRemovePages * __pagesize;
|
||||||
|
|
||||||
DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages);
|
DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages);
|
||||||
|
|
||||||
m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes);
|
m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes);
|
||||||
|
|
||||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||||
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
|
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pages_reserved = newPages;
|
m_pages_reserved = newPages;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -377,27 +404,27 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxString PageProtectionMode::ToString() const
|
wxString PageProtectionMode::ToString() const
|
||||||
{
|
{
|
||||||
wxString modeStr;
|
wxString modeStr;
|
||||||
|
|
||||||
if (m_read)
|
if (m_read)
|
||||||
modeStr += L"Read";
|
modeStr += L"Read";
|
||||||
if (m_write)
|
if (m_write)
|
||||||
modeStr += L"Write";
|
modeStr += L"Write";
|
||||||
if (m_exec)
|
if (m_exec)
|
||||||
modeStr += L"Exec";
|
modeStr += L"Exec";
|
||||||
|
|
||||||
if (modeStr.IsEmpty())
|
if (modeStr.IsEmpty())
|
||||||
return L"NoAccess";
|
return L"NoAccess";
|
||||||
if (modeStr.Length() <= 5)
|
if (modeStr.Length() <= 5)
|
||||||
modeStr += L"Only";
|
modeStr += L"Only";
|
||||||
|
|
||||||
return modeStr;
|
return modeStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Common HostSys implementation
|
// Common HostSys implementation
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
void HostSys::Munmap(void *base, size_t size)
|
void HostSys::Munmap(void* base, size_t size)
|
||||||
{
|
{
|
||||||
Munmap((uptr)base, size);
|
Munmap((uptr)base, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,136 +18,146 @@
|
||||||
#include "common/RedtapeWindows.h"
|
#include "common/RedtapeWindows.h"
|
||||||
#include "common/PageFaultSource.h"
|
#include "common/PageFaultSource.h"
|
||||||
|
|
||||||
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
|
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||||
{
|
{
|
||||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
// Note: This exception can be accessed by the EE or MTVU thread
|
// Note: This exception can be accessed by the EE or MTVU thread
|
||||||
// Source_PageFault is a global variable with its own state information
|
// Source_PageFault is a global variable with its own state information
|
||||||
// so for now we lock this exception code unless someone can fix this better...
|
// so for now we lock this exception code unless someone can fix this better...
|
||||||
Threading::ScopedLock lock(PageFault_Mutex);
|
Threading::ScopedLock lock(PageFault_Mutex);
|
||||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
||||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
|
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||||
{
|
{
|
||||||
// Prevent recursive exception filtering by catching the exception from the filter here.
|
// Prevent recursive exception filtering by catching the exception from the filter here.
|
||||||
// In the event that the filter causes an access violation (happened during shutdown
|
// In the event that the filter causes an access violation (happened during shutdown
|
||||||
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
||||||
// exception.
|
// exception.
|
||||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||||
// work but I don't fully understand why some do and some don't.
|
// work but I don't fully understand why some do and some don't.
|
||||||
__try {
|
__try
|
||||||
return DoSysPageFaultExceptionFilter(eps);
|
{
|
||||||
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
return DoSysPageFaultExceptionFilter(eps);
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
}
|
||||||
}
|
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
||||||
|
{
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _platform_InstallSignalHandler()
|
void _platform_InstallSignalHandler()
|
||||||
{
|
{
|
||||||
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
|
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
|
||||||
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DWORD ConvertToWinApi(const PageProtectionMode &mode)
|
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
DWORD winmode = PAGE_NOACCESS;
|
DWORD winmode = PAGE_NOACCESS;
|
||||||
|
|
||||||
// Windows has some really bizarre memory protection enumeration that uses bitwise
|
// Windows has some really bizarre memory protection enumeration that uses bitwise
|
||||||
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
||||||
// microsoft days wasn't a very good coder, me thinks. --air
|
// microsoft days wasn't a very good coder, me thinks. --air
|
||||||
|
|
||||||
if (mode.CanExecute()) {
|
if (mode.CanExecute())
|
||||||
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
{
|
||||||
} else if (mode.CanRead()) {
|
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||||
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
}
|
||||||
}
|
else if (mode.CanRead())
|
||||||
|
{
|
||||||
|
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
||||||
|
}
|
||||||
|
|
||||||
return winmode;
|
return winmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *HostSys::MmapReservePtr(void *base, size_t size)
|
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||||
{
|
{
|
||||||
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
|
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode)
|
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
void *result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
|
void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
|
||||||
if (result)
|
if (result)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const DWORD errcode = GetLastError();
|
const DWORD errcode = GetLastError();
|
||||||
if (errcode == ERROR_COMMITMENT_MINIMUM) {
|
if (errcode == ERROR_COMMITMENT_MINIMUM)
|
||||||
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
{
|
||||||
Sleep(1000); // Cut windows some time to rework its memory...
|
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
||||||
} else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) {
|
Sleep(1000); // Cut windows some time to rework its memory...
|
||||||
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
}
|
||||||
return false;
|
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
|
||||||
}
|
{
|
||||||
|
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!pxDoOutOfMemory)
|
if (!pxDoOutOfMemory)
|
||||||
return false;
|
return false;
|
||||||
pxDoOutOfMemory(size);
|
pxDoOutOfMemory(size);
|
||||||
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
|
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MmapResetPtr(void *base, size_t size)
|
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||||
{
|
{
|
||||||
VirtualFree(base, size, MEM_DECOMMIT);
|
VirtualFree(base, size, MEM_DECOMMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *HostSys::MmapReserve(uptr base, size_t size)
|
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
return MmapReservePtr((void *)base, size);
|
return MmapReservePtr((void*)base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode)
|
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
return MmapCommitPtr((void *)base, size, mode);
|
return MmapCommitPtr((void*)base, size, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MmapReset(uptr base, size_t size)
|
void HostSys::MmapReset(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
MmapResetPtr((void *)base, size);
|
MmapResetPtr((void*)base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *HostSys::Mmap(uptr base, size_t size)
|
void* HostSys::Mmap(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
return VirtualAlloc((void *)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::Munmap(uptr base, size_t size)
|
void HostSys::Munmap(uptr base, size_t size)
|
||||||
{
|
{
|
||||||
if (!base)
|
if (!base)
|
||||||
return;
|
return;
|
||||||
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||||
VirtualFree((void *)base, 0, MEM_RELEASE);
|
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
|
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
|
||||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||||
__pagesize, __pagesize, size, size));
|
__pagesize, __pagesize, size, size));
|
||||||
|
|
||||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||||
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect)) {
|
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect))
|
||||||
Exception::WinApiError apiError;
|
{
|
||||||
|
Exception::WinApiError apiError;
|
||||||
|
|
||||||
apiError.SetDiagMsg(
|
apiError.SetDiagMsg(
|
||||||
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
|
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
|
||||||
|
|
||||||
pxFailDev(apiError.FormatDiagnosticMessage());
|
pxFailDev(apiError.FormatDiagnosticMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,115 +21,118 @@
|
||||||
|
|
||||||
__fi void Threading::Sleep(int ms)
|
__fi void Threading::Sleep(int ms)
|
||||||
{
|
{
|
||||||
::Sleep(ms);
|
::Sleep(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
||||||
// improve performance and reduce cpu power consumption.
|
// improve performance and reduce cpu power consumption.
|
||||||
__fi void Threading::SpinWait()
|
__fi void Threading::SpinWait()
|
||||||
{
|
{
|
||||||
_mm_pause();
|
_mm_pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void Threading::EnableHiresScheduler()
|
__fi void Threading::EnableHiresScheduler()
|
||||||
{
|
{
|
||||||
// This improves accuracy of Sleep() by some amount, and only adds a negligible amount of
|
// This improves accuracy of Sleep() by some amount, and only adds a negligible amount of
|
||||||
// overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in
|
// overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in
|
||||||
// particular may have a scheduler Period of 15 or 20ms to extend battery life.
|
// particular may have a scheduler Period of 15 or 20ms to extend battery life.
|
||||||
|
|
||||||
// (note: this same trick is used by most multimedia software and games)
|
// (note: this same trick is used by most multimedia software and games)
|
||||||
|
|
||||||
timeBeginPeriod(1);
|
timeBeginPeriod(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void Threading::DisableHiresScheduler()
|
__fi void Threading::DisableHiresScheduler()
|
||||||
{
|
{
|
||||||
timeEndPeriod(1);
|
timeEndPeriod(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
|
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
|
||||||
// packed (but for any x86 CPU and microsoft compiler, they will be).
|
// packed (but for any x86 CPU and microsoft compiler, they will be).
|
||||||
union FileTimeSucks
|
union FileTimeSucks
|
||||||
{
|
{
|
||||||
FILETIME filetime;
|
FILETIME filetime;
|
||||||
u64 u64time;
|
u64 u64time;
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 Threading::GetThreadCpuTime()
|
u64 Threading::GetThreadCpuTime()
|
||||||
{
|
{
|
||||||
FileTimeSucks user, kernel;
|
FileTimeSucks user, kernel;
|
||||||
FILETIME dummy;
|
FILETIME dummy;
|
||||||
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
|
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
|
||||||
return user.u64time + kernel.u64time;
|
return user.u64time + kernel.u64time;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Threading::GetThreadTicksPerSecond()
|
u64 Threading::GetThreadTicksPerSecond()
|
||||||
{
|
{
|
||||||
return 10000000;
|
return 10000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Threading::pxThread::GetCpuTime() const
|
u64 Threading::pxThread::GetCpuTime() const
|
||||||
{
|
{
|
||||||
if (!m_native_handle)
|
if (!m_native_handle)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FileTimeSucks user, kernel;
|
FileTimeSucks user, kernel;
|
||||||
FILETIME dummy;
|
FILETIME dummy;
|
||||||
|
|
||||||
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
|
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
|
||||||
return user.u64time + kernel.u64time;
|
return user.u64time + kernel.u64time;
|
||||||
|
|
||||||
return 0; // thread prolly doesn't exist anymore.
|
return 0; // thread prolly doesn't exist anymore.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||||
{
|
{
|
||||||
// OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
|
// OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
|
||||||
// however we own our process threads, so shouldn't matter in any case...
|
// however we own our process threads, so shouldn't matter in any case...
|
||||||
|
|
||||||
m_native_id = (uptr)GetCurrentThreadId();
|
m_native_id = (uptr)GetCurrentThreadId();
|
||||||
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
|
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
|
||||||
|
|
||||||
pxAssertDev(m_native_handle, wxNullChar);
|
pxAssertDev(m_native_handle, wxNullChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||||
{
|
{
|
||||||
CloseHandle((HANDLE)m_native_handle);
|
CloseHandle((HANDLE)m_native_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::SetNameOfCurrentThread(const char *name)
|
void Threading::SetNameOfCurrentThread(const char* name)
|
||||||
{
|
{
|
||||||
// This feature needs Windows headers and MSVC's SEH support:
|
// This feature needs Windows headers and MSVC's SEH support:
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_MSC_VER)
|
#if defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
|
||||||
// This code sample was borrowed form some obscure MSDN article.
|
// This code sample was borrowed form some obscure MSDN article.
|
||||||
// In a rare bout of sanity, it's an actual Microsoft-published hack
|
// In a rare bout of sanity, it's an actual Microsoft-published hack
|
||||||
// that actually works!
|
// that actually works!
|
||||||
|
|
||||||
static const int MS_VC_EXCEPTION = 0x406D1388;
|
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push, 8)
|
||||||
struct THREADNAME_INFO
|
struct THREADNAME_INFO
|
||||||
{
|
{
|
||||||
DWORD dwType; // Must be 0x1000.
|
DWORD dwType; // Must be 0x1000.
|
||||||
LPCSTR szName; // Pointer to name (in user addr space).
|
LPCSTR szName; // Pointer to name (in user addr space).
|
||||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
THREADNAME_INFO info;
|
THREADNAME_INFO info;
|
||||||
info.dwType = 0x1000;
|
info.dwType = 0x1000;
|
||||||
info.szName = name;
|
info.szName = name;
|
||||||
info.dwThreadID = GetCurrentThreadId();
|
info.dwThreadID = GetCurrentThreadId();
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
__try {
|
__try
|
||||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
|
{
|
||||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||||
}
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
// FreeBSD/OsX need something far more complicated (apparently)
|
// FreeBSD/OsX need something far more complicated (apparently)
|
||||||
void x86capabilities::CountLogicalCores()
|
void x86capabilities::CountLogicalCores()
|
||||||
{
|
{
|
||||||
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
|
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
|
||||||
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
|
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
|
||||||
// alternatives, apparently.
|
// alternatives, apparently.
|
||||||
LogicalCores = wxThread::GetCPUCount();
|
LogicalCores = wxThread::GetCPUCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not implemented yet for linux (see cpudetect_internal.h for details)
|
// Not implemented yet for linux (see cpudetect_internal.h for details)
|
||||||
|
|
|
@ -20,65 +20,66 @@
|
||||||
|
|
||||||
void x86capabilities::CountLogicalCores()
|
void x86capabilities::CountLogicalCores()
|
||||||
{
|
{
|
||||||
DWORD_PTR vProcessCPUs;
|
DWORD_PTR vProcessCPUs;
|
||||||
DWORD_PTR vSystemCPUs;
|
DWORD_PTR vSystemCPUs;
|
||||||
|
|
||||||
LogicalCores = 1;
|
LogicalCores = 1;
|
||||||
|
|
||||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint CPUs = 0;
|
uint CPUs = 0;
|
||||||
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
||||||
if (vSystemCPUs & bit)
|
if (vSystemCPUs & bit)
|
||||||
CPUs++;
|
CPUs++;
|
||||||
|
|
||||||
LogicalCores = CPUs;
|
LogicalCores = CPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleCoreAffinity::SingleCoreAffinity()
|
SingleCoreAffinity::SingleCoreAffinity()
|
||||||
{
|
{
|
||||||
s_threadId = nullptr;
|
s_threadId = nullptr;
|
||||||
s_oldmask = ERROR_INVALID_PARAMETER;
|
s_oldmask = ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
DWORD_PTR availProcCpus;
|
DWORD_PTR availProcCpus;
|
||||||
DWORD_PTR availSysCpus;
|
DWORD_PTR availSysCpus;
|
||||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
|
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int cpu = 0;
|
int cpu = 0;
|
||||||
DWORD_PTR affinityMask;
|
DWORD_PTR affinityMask;
|
||||||
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
|
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
|
||||||
if (availProcCpus & affinityMask)
|
if (availProcCpus & affinityMask)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
s_threadId = GetCurrentThread();
|
s_threadId = GetCurrentThread();
|
||||||
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
||||||
|
|
||||||
if (s_oldmask == ERROR_INVALID_PARAMETER) {
|
if (s_oldmask == ERROR_INVALID_PARAMETER)
|
||||||
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
{
|
||||||
Console.Warning(
|
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
||||||
"CpuDetect: SetThreadAffinityMask failed...\n"
|
Console.Warning(
|
||||||
"\tSystem Affinity : 0x%0*x\n"
|
"CpuDetect: SetThreadAffinityMask failed...\n"
|
||||||
"\tProcess Affinity: 0x%0*x\n"
|
"\tSystem Affinity : 0x%0*x\n"
|
||||||
"\tAttempted Thread Affinity CPU: %i",
|
"\tProcess Affinity: 0x%0*x\n"
|
||||||
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
|
"\tAttempted Thread Affinity CPU: %i",
|
||||||
}
|
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
|
||||||
|
}
|
||||||
|
|
||||||
Sleep(2);
|
Sleep(2);
|
||||||
|
|
||||||
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
||||||
// means that the current thread will need to be switched to Core 0 if it's currently
|
// means that the current thread will need to be switched to Core 0 if it's currently
|
||||||
// scheduled on a difference cpu/core. However, Windows does not necessarily perform
|
// scheduled on a difference cpu/core. However, Windows does not necessarily perform
|
||||||
// that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent
|
// that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent
|
||||||
// on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time
|
// on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time
|
||||||
// to issue a timeslice and move our thread to Core 0. Without this, it tends to move
|
// to issue a timeslice and move our thread to Core 0. Without this, it tends to move
|
||||||
// the thread during the cpuSpeed test instead, causing totally wacky results.
|
// the thread during the cpuSpeed test instead, causing totally wacky results.
|
||||||
};
|
};
|
||||||
|
|
||||||
SingleCoreAffinity::~SingleCoreAffinity()
|
SingleCoreAffinity::~SingleCoreAffinity()
|
||||||
{
|
{
|
||||||
if (s_oldmask != ERROR_INVALID_PARAMETER)
|
if (s_oldmask != ERROR_INVALID_PARAMETER)
|
||||||
SetThreadAffinityMask(s_threadId, s_oldmask);
|
SetThreadAffinityMask(s_threadId, s_oldmask);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,17 +19,17 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
|
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
|
||||||
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
|
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
|
||||||
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
|
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
|
||||||
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
|
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
|
||||||
|
|
||||||
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const
|
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const
|
||||||
{
|
{
|
||||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||||
}
|
}
|
||||||
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const
|
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const
|
||||||
{
|
{
|
||||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -31,12 +31,12 @@
|
||||||
|
|
||||||
static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count)
|
static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count)
|
||||||
{
|
{
|
||||||
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType)
|
static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType)
|
||||||
{
|
{
|
||||||
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,23 +46,23 @@ using namespace x86Emitter;
|
||||||
__aligned16 x86capabilities x86caps;
|
__aligned16 x86capabilities x86caps;
|
||||||
|
|
||||||
x86capabilities::x86capabilities()
|
x86capabilities::x86capabilities()
|
||||||
: isIdentified(false)
|
: isIdentified(false)
|
||||||
, VendorID(x86Vendor_Unknown)
|
, VendorID(x86Vendor_Unknown)
|
||||||
, FamilyID(0)
|
, FamilyID(0)
|
||||||
, Model(0)
|
, Model(0)
|
||||||
, TypeID(0)
|
, TypeID(0)
|
||||||
, StepID(0)
|
, StepID(0)
|
||||||
, Flags(0)
|
, Flags(0)
|
||||||
, Flags2(0)
|
, Flags2(0)
|
||||||
, EFlags(0)
|
, EFlags(0)
|
||||||
, EFlags2(0)
|
, EFlags2(0)
|
||||||
, SEFlag(0)
|
, SEFlag(0)
|
||||||
, AllCapabilities(0)
|
, AllCapabilities(0)
|
||||||
, PhysicalCores(0)
|
, PhysicalCores(0)
|
||||||
, LogicalCores(0)
|
, LogicalCores(0)
|
||||||
{
|
{
|
||||||
memzero(VendorName);
|
memzero(VendorName);
|
||||||
memzero(FamilyName);
|
memzero(FamilyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
||||||
|
@ -72,28 +72,29 @@ x86capabilities::x86capabilities()
|
||||||
// Note: recSSE was deleted
|
// Note: recSSE was deleted
|
||||||
void x86capabilities::SIMD_EstablishMXCSRmask()
|
void x86capabilities::SIMD_EstablishMXCSRmask()
|
||||||
{
|
{
|
||||||
if (!hasStreamingSIMDExtensions)
|
if (!hasStreamingSIMDExtensions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
||||||
|
|
||||||
if (hasStreamingSIMD2Extensions) {
|
if (hasStreamingSIMD2Extensions)
|
||||||
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
{
|
||||||
// detect MXCSR masking features of the cpu, so we use it's result below
|
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
||||||
// and override this.
|
// detect MXCSR masking features of the cpu, so we use it's result below
|
||||||
|
// and override this.
|
||||||
|
|
||||||
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
||||||
}
|
}
|
||||||
|
|
||||||
__aligned16 u8 targetFXSAVE[512];
|
__aligned16 u8 targetFXSAVE[512];
|
||||||
|
|
||||||
// Work for recent enough GCC/CLANG/MSVC 2012
|
// Work for recent enough GCC/CLANG/MSVC 2012
|
||||||
_fxsave(&targetFXSAVE);
|
_fxsave(&targetFXSAVE);
|
||||||
|
|
||||||
u32 result;
|
u32 result;
|
||||||
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
|
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
MXCSR_Mask.bitmask = result;
|
MXCSR_Mask.bitmask = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter
|
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter
|
||||||
|
@ -103,221 +104,229 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
|
||||||
// by the operating system task switches.
|
// by the operating system task switches.
|
||||||
s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
||||||
{
|
{
|
||||||
u64 timeStart, timeStop;
|
u64 timeStart, timeStop;
|
||||||
s64 startCycle, endCycle;
|
s64 startCycle, endCycle;
|
||||||
|
|
||||||
if (!hasTimeStampCounter)
|
if (!hasTimeStampCounter)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SingleCoreAffinity affinity_lock;
|
SingleCoreAffinity affinity_lock;
|
||||||
|
|
||||||
// Align the cpu execution to a cpuTick boundary.
|
// Align the cpu execution to a cpuTick boundary.
|
||||||
|
|
||||||
do {
|
do
|
||||||
timeStart = GetCPUTicks();
|
{
|
||||||
startCycle = __rdtsc();
|
timeStart = GetCPUTicks();
|
||||||
} while (GetCPUTicks() == timeStart);
|
startCycle = __rdtsc();
|
||||||
|
} while (GetCPUTicks() == timeStart);
|
||||||
|
|
||||||
do {
|
do
|
||||||
timeStop = GetCPUTicks();
|
{
|
||||||
endCycle = __rdtsc();
|
timeStop = GetCPUTicks();
|
||||||
} while ((timeStop - timeStart) < time);
|
endCycle = __rdtsc();
|
||||||
|
} while ((timeStop - timeStart) < time);
|
||||||
|
|
||||||
s64 cycleCount = endCycle - startCycle;
|
s64 cycleCount = endCycle - startCycle;
|
||||||
s64 timeCount = timeStop - timeStart;
|
s64 timeCount = timeStop - timeStart;
|
||||||
s64 overrun = timeCount - time;
|
s64 overrun = timeCount - time;
|
||||||
if (!overrun)
|
if (!overrun)
|
||||||
return cycleCount;
|
return cycleCount;
|
||||||
|
|
||||||
// interference could cause us to overshoot the target time, compensate:
|
// interference could cause us to overshoot the target time, compensate:
|
||||||
|
|
||||||
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
||||||
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
||||||
|
|
||||||
return (s64)newCycleCount;
|
return (s64)newCycleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString x86capabilities::GetTypeName() const
|
wxString x86capabilities::GetTypeName() const
|
||||||
{
|
{
|
||||||
switch (TypeID) {
|
switch (TypeID)
|
||||||
case 0:
|
{
|
||||||
return L"Standard OEM";
|
case 0:
|
||||||
case 1:
|
return L"Standard OEM";
|
||||||
return L"Overdrive";
|
case 1:
|
||||||
case 2:
|
return L"Overdrive";
|
||||||
return L"Dual";
|
case 2:
|
||||||
case 3:
|
return L"Dual";
|
||||||
return L"Reserved";
|
case 3:
|
||||||
default:
|
return L"Reserved";
|
||||||
return L"Unknown";
|
default:
|
||||||
}
|
return L"Unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void x86capabilities::CountCores()
|
void x86capabilities::CountCores()
|
||||||
{
|
{
|
||||||
Identify();
|
Identify();
|
||||||
|
|
||||||
s32 regs[4];
|
s32 regs[4];
|
||||||
u32 cmds;
|
u32 cmds;
|
||||||
|
|
||||||
cpuid(regs, 0x80000000);
|
cpuid(regs, 0x80000000);
|
||||||
cmds = regs[0];
|
cmds = regs[0];
|
||||||
|
|
||||||
// detect multicore for AMD cpu
|
// detect multicore for AMD cpu
|
||||||
|
|
||||||
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD)) {
|
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
|
||||||
// AMD note: they don't support hyperthreading, but they like to flag this true
|
{
|
||||||
// anyway. Let's force-unflag it until we come up with a better solution.
|
// AMD note: they don't support hyperthreading, but they like to flag this true
|
||||||
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
// anyway. Let's force-unflag it until we come up with a better solution.
|
||||||
// not seem to do this) --air
|
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
||||||
hasMultiThreading = 0;
|
// not seem to do this) --air
|
||||||
}
|
hasMultiThreading = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// This will assign values into LogicalCores and PhysicalCores
|
// This will assign values into LogicalCores and PhysicalCores
|
||||||
CountLogicalCores();
|
CountLogicalCores();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *tbl_x86vendors[] =
|
static const char* tbl_x86vendors[] =
|
||||||
{
|
{
|
||||||
"GenuineIntel",
|
"GenuineIntel",
|
||||||
"AuthenticAMD",
|
"AuthenticAMD",
|
||||||
"Unknown ",
|
"Unknown ",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
|
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
|
||||||
// the cpuSpeed and the mxcsr masks. Those must be completed manually.
|
// the cpuSpeed and the mxcsr masks. Those must be completed manually.
|
||||||
void x86capabilities::Identify()
|
void x86capabilities::Identify()
|
||||||
{
|
{
|
||||||
if (isIdentified)
|
if (isIdentified)
|
||||||
return;
|
return;
|
||||||
isIdentified = true;
|
isIdentified = true;
|
||||||
|
|
||||||
s32 regs[4];
|
s32 regs[4];
|
||||||
u32 cmds;
|
u32 cmds;
|
||||||
|
|
||||||
memzero(VendorName);
|
memzero(VendorName);
|
||||||
cpuid(regs, 0);
|
cpuid(regs, 0);
|
||||||
|
|
||||||
cmds = regs[0];
|
cmds = regs[0];
|
||||||
memcpy(&VendorName[0], ®s[1], 4);
|
memcpy(&VendorName[0], ®s[1], 4);
|
||||||
memcpy(&VendorName[4], ®s[3], 4);
|
memcpy(&VendorName[4], ®s[3], 4);
|
||||||
memcpy(&VendorName[8], ®s[2], 4);
|
memcpy(&VendorName[8], ®s[2], 4);
|
||||||
|
|
||||||
// Determine Vendor Specifics!
|
// Determine Vendor Specifics!
|
||||||
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
||||||
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
||||||
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
||||||
|
|
||||||
int vid;
|
int vid;
|
||||||
for (vid = 0; vid < x86Vendor_Unknown; ++vid) {
|
for (vid = 0; vid < x86Vendor_Unknown; ++vid)
|
||||||
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
{
|
||||||
break;
|
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
||||||
}
|
break;
|
||||||
VendorID = static_cast<x86VendorType>(vid);
|
}
|
||||||
|
VendorID = static_cast<x86VendorType>(vid);
|
||||||
|
|
||||||
if (cmds >= 0x00000001) {
|
if (cmds >= 0x00000001)
|
||||||
cpuid(regs, 0x00000001);
|
{
|
||||||
|
cpuid(regs, 0x00000001);
|
||||||
|
|
||||||
StepID = regs[0] & 0xf;
|
StepID = regs[0] & 0xf;
|
||||||
Model = (regs[0] >> 4) & 0xf;
|
Model = (regs[0] >> 4) & 0xf;
|
||||||
FamilyID = (regs[0] >> 8) & 0xf;
|
FamilyID = (regs[0] >> 8) & 0xf;
|
||||||
TypeID = (regs[0] >> 12) & 0x3;
|
TypeID = (regs[0] >> 12) & 0x3;
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
|
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
|
||||||
#endif
|
#endif
|
||||||
Flags = regs[3];
|
Flags = regs[3];
|
||||||
Flags2 = regs[2];
|
Flags2 = regs[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmds >= 0x00000007) {
|
if (cmds >= 0x00000007)
|
||||||
// Note: ECX must be 0 for AVX2 detection.
|
{
|
||||||
cpuidex(regs, 0x00000007, 0);
|
// Note: ECX must be 0 for AVX2 detection.
|
||||||
|
cpuidex(regs, 0x00000007, 0);
|
||||||
|
|
||||||
SEFlag = regs[1];
|
SEFlag = regs[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
cpuid(regs, 0x80000000);
|
cpuid(regs, 0x80000000);
|
||||||
cmds = regs[0];
|
cmds = regs[0];
|
||||||
if (cmds >= 0x80000001) {
|
if (cmds >= 0x80000001)
|
||||||
cpuid(regs, 0x80000001);
|
{
|
||||||
|
cpuid(regs, 0x80000001);
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
|
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
|
||||||
#endif
|
#endif
|
||||||
EFlags2 = regs[2];
|
EFlags2 = regs[2];
|
||||||
EFlags = regs[3];
|
EFlags = regs[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
memzero(FamilyName);
|
memzero(FamilyName);
|
||||||
cpuid((int *)FamilyName, 0x80000002);
|
cpuid((int*)FamilyName, 0x80000002);
|
||||||
cpuid((int *)(FamilyName + 16), 0x80000003);
|
cpuid((int*)(FamilyName + 16), 0x80000003);
|
||||||
cpuid((int *)(FamilyName + 32), 0x80000004);
|
cpuid((int*)(FamilyName + 32), 0x80000004);
|
||||||
|
|
||||||
hasFloatingPointUnit = (Flags >> 0) & 1;
|
hasFloatingPointUnit = (Flags >> 0) & 1;
|
||||||
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
|
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
|
||||||
hasDebuggingExtensions = (Flags >> 2) & 1;
|
hasDebuggingExtensions = (Flags >> 2) & 1;
|
||||||
hasPageSizeExtensions = (Flags >> 3) & 1;
|
hasPageSizeExtensions = (Flags >> 3) & 1;
|
||||||
hasTimeStampCounter = (Flags >> 4) & 1;
|
hasTimeStampCounter = (Flags >> 4) & 1;
|
||||||
hasModelSpecificRegisters = (Flags >> 5) & 1;
|
hasModelSpecificRegisters = (Flags >> 5) & 1;
|
||||||
hasPhysicalAddressExtension = (Flags >> 6) & 1;
|
hasPhysicalAddressExtension = (Flags >> 6) & 1;
|
||||||
hasMachineCheckArchitecture = (Flags >> 7) & 1;
|
hasMachineCheckArchitecture = (Flags >> 7) & 1;
|
||||||
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
|
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
|
||||||
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
|
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
|
||||||
hasSEPFastSystemCall = (Flags >> 11) & 1;
|
hasSEPFastSystemCall = (Flags >> 11) & 1;
|
||||||
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
|
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
|
||||||
hasPTEGlobalFlag = (Flags >> 13) & 1;
|
hasPTEGlobalFlag = (Flags >> 13) & 1;
|
||||||
hasMachineCheckArchitecture = (Flags >> 14) & 1;
|
hasMachineCheckArchitecture = (Flags >> 14) & 1;
|
||||||
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
|
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
|
||||||
hasFGPageAttributeTable = (Flags >> 16) & 1;
|
hasFGPageAttributeTable = (Flags >> 16) & 1;
|
||||||
has36bitPageSizeExtension = (Flags >> 17) & 1;
|
has36bitPageSizeExtension = (Flags >> 17) & 1;
|
||||||
hasProcessorSerialNumber = (Flags >> 18) & 1;
|
hasProcessorSerialNumber = (Flags >> 18) & 1;
|
||||||
hasCFLUSHInstruction = (Flags >> 19) & 1;
|
hasCFLUSHInstruction = (Flags >> 19) & 1;
|
||||||
hasDebugStore = (Flags >> 21) & 1;
|
hasDebugStore = (Flags >> 21) & 1;
|
||||||
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
|
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
|
||||||
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
|
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
|
||||||
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
|
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
|
||||||
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
|
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
|
||||||
hasSelfSnoop = (Flags >> 27) & 1;
|
hasSelfSnoop = (Flags >> 27) & 1;
|
||||||
hasMultiThreading = (Flags >> 28) & 1;
|
hasMultiThreading = (Flags >> 28) & 1;
|
||||||
hasThermalMonitor = (Flags >> 29) & 1;
|
hasThermalMonitor = (Flags >> 29) & 1;
|
||||||
hasIntel64BitArchitecture = (Flags >> 30) & 1;
|
hasIntel64BitArchitecture = (Flags >> 30) & 1;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
|
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
|
||||||
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
|
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
|
||||||
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
|
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
|
||||||
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
|
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
|
||||||
|
|
||||||
if ((Flags2 >> 27) & 1) // OSXSAVE
|
if ((Flags2 >> 27) & 1) // OSXSAVE
|
||||||
{
|
{
|
||||||
// Note: In theory, we should use xgetbv to check OS support
|
// Note: In theory, we should use xgetbv to check OS support
|
||||||
// but all OSes we officially run under support it
|
// but all OSes we officially run under support it
|
||||||
// and its intrinsic requires extra compiler flags
|
// and its intrinsic requires extra compiler flags
|
||||||
hasAVX = (Flags2 >> 28) & 1; //avx
|
hasAVX = (Flags2 >> 28) & 1; //avx
|
||||||
hasFMA = (Flags2 >> 12) & 1; //fma
|
hasFMA = (Flags2 >> 12) & 1; //fma
|
||||||
hasAVX2 = (SEFlag >> 5) & 1; //avx2
|
hasAVX2 = (SEFlag >> 5) & 1; //avx2
|
||||||
}
|
}
|
||||||
|
|
||||||
hasBMI1 = (SEFlag >> 3) & 1;
|
hasBMI1 = (SEFlag >> 3) & 1;
|
||||||
hasBMI2 = (SEFlag >> 8) & 1;
|
hasBMI2 = (SEFlag >> 8) & 1;
|
||||||
|
|
||||||
// Ones only for AMDs:
|
// Ones only for AMDs:
|
||||||
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
|
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
|
||||||
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
|
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
|
||||||
|
|
||||||
isIdentified = true;
|
isIdentified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 x86capabilities::CalculateMHz() const
|
u32 x86capabilities::CalculateMHz() const
|
||||||
{
|
{
|
||||||
InitCPUTicks();
|
InitCPUTicks();
|
||||||
u64 span = GetTickFrequency();
|
u64 span = GetTickFrequency();
|
||||||
|
|
||||||
if ((span % 1000) < 400) // helps minimize rounding errors
|
if ((span % 1000) < 400) // helps minimize rounding errors
|
||||||
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
|
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
|
||||||
else
|
else
|
||||||
return (u32)(_CPUSpeedHz(span / 500) / 2000);
|
return (u32)(_CPUSpeedHz(span / 500) / 2000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,11 @@ class SingleCoreAffinity
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE s_threadId;
|
HANDLE s_threadId;
|
||||||
DWORD_PTR s_oldmask;
|
DWORD_PTR s_oldmask;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SingleCoreAffinity();
|
SingleCoreAffinity();
|
||||||
virtual ~SingleCoreAffinity();
|
virtual ~SingleCoreAffinity();
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
/* fld m32 to fpu reg stack */
|
/* fld m32 to fpu reg stack */
|
||||||
emitterT void FLD32(u32 from)
|
emitterT void FLD32(u32 from)
|
||||||
{
|
{
|
||||||
xWrite8(0xD9);
|
xWrite8(0xD9);
|
||||||
ModRM(0, 0x0, DISP32);
|
ModRM(0, 0x0, DISP32);
|
||||||
xWrite32(MEMADDR(from, 4));
|
xWrite32(MEMADDR(from, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fld st(i)
|
// fld st(i)
|
||||||
|
@ -34,9 +34,9 @@ emitterT void FLDL2E() { xWrite16(0xead9); }
|
||||||
/* fstp m32 from fpu reg stack */
|
/* fstp m32 from fpu reg stack */
|
||||||
emitterT void FSTP32(u32 to)
|
emitterT void FSTP32(u32 to)
|
||||||
{
|
{
|
||||||
xWrite8(0xD9);
|
xWrite8(0xD9);
|
||||||
ModRM(0, 0x3, DISP32);
|
ModRM(0, 0x3, DISP32);
|
||||||
xWrite32(MEMADDR(to, 4));
|
xWrite32(MEMADDR(to, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fstp st(i)
|
// fstp st(i)
|
||||||
|
@ -52,21 +52,21 @@ emitterT void FSIN(void) { xWrite16(0xfed9); }
|
||||||
/* fadd ST(0) to fpu reg stack ST(src) */
|
/* fadd ST(0) to fpu reg stack ST(src) */
|
||||||
emitterT void FADD320toR(x86IntRegType src)
|
emitterT void FADD320toR(x86IntRegType src)
|
||||||
{
|
{
|
||||||
xWrite8(0xDC);
|
xWrite8(0xDC);
|
||||||
xWrite8(0xC0 + src);
|
xWrite8(0xC0 + src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fsub ST(src) to fpu reg stack ST(0) */
|
/* fsub ST(src) to fpu reg stack ST(0) */
|
||||||
emitterT void FSUB32Rto0(x86IntRegType src)
|
emitterT void FSUB32Rto0(x86IntRegType src)
|
||||||
{
|
{
|
||||||
xWrite8(0xD8);
|
xWrite8(0xD8);
|
||||||
xWrite8(0xE0 + src);
|
xWrite8(0xE0 + src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmul m32 to fpu reg stack */
|
/* fmul m32 to fpu reg stack */
|
||||||
emitterT void FMUL32(u32 from)
|
emitterT void FMUL32(u32 from)
|
||||||
{
|
{
|
||||||
xWrite8(0xD8);
|
xWrite8(0xD8);
|
||||||
ModRM(0, 0x1, DISP32);
|
ModRM(0, 0x1, DISP32);
|
||||||
xWrite32(MEMADDR(from, 4));
|
xWrite32(MEMADDR(from, 4));
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,222 +34,237 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// Group 1 Instructions - ADD, SUB, ADC, etc.
|
// Group 1 Instructions - ADD, SUB, ADC, etc.
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
|
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
|
||||||
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
|
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
|
||||||
// with one of the other overloads).
|
// with one of the other overloads).
|
||||||
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess &sibdest, int imm)
|
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
|
||||||
{
|
{
|
||||||
if (sibdest.Is8BitOp()) {
|
if (sibdest.Is8BitOp())
|
||||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
{
|
||||||
|
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
||||||
|
|
||||||
xWrite<s8>(imm);
|
xWrite<s8>(imm);
|
||||||
} else {
|
}
|
||||||
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
else
|
||||||
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
{
|
||||||
|
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
||||||
|
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
||||||
|
|
||||||
if (is_s8(imm))
|
if (is_s8(imm))
|
||||||
xWrite<s8>(imm);
|
xWrite<s8>(imm);
|
||||||
else
|
else
|
||||||
sibdest.xWriteImm(imm);
|
sibdest.xWriteImm(imm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from)
|
void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from)
|
||||||
{
|
{
|
||||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||||
|
|
||||||
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||||
xOpWrite(to.GetPrefix16(), opcode, from, to);
|
xOpWrite(to.GetPrefix16(), opcode, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid &sibdest, const xRegisterInt &from)
|
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid& sibdest, const xRegisterInt& from)
|
||||||
{
|
{
|
||||||
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||||
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
|
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xIndirectVoid &sibsrc)
|
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xIndirectVoid& sibsrc)
|
||||||
{
|
{
|
||||||
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
|
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
|
||||||
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
|
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, int imm)
|
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
|
||||||
{
|
{
|
||||||
if (!to.Is8BitOp() && is_s8(imm)) {
|
if (!to.Is8BitOp() && is_s8(imm))
|
||||||
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
{
|
||||||
xWrite<s8>(imm);
|
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
||||||
} else {
|
xWrite<s8>(imm);
|
||||||
if (to.IsAccumulator()) {
|
}
|
||||||
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
else
|
||||||
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
{
|
||||||
} else {
|
if (to.IsAccumulator())
|
||||||
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
{
|
||||||
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
||||||
}
|
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||||
to.xWriteImm(imm);
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
||||||
|
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||||
|
}
|
||||||
|
to.xWriteImm(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define ImplementGroup1(g1type, insttype) \
|
#define ImplementGroup1(g1type, insttype) \
|
||||||
void g1type::operator()(const xRegisterInt &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \
|
void g1type::operator()(const xRegisterInt& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||||
void g1type::operator()(const xIndirectVoid &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \
|
void g1type::operator()(const xIndirectVoid& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||||
void g1type::operator()(const xRegisterInt &to, const xIndirectVoid &from) const { _g1_EmitOp(insttype, to, from); } \
|
void g1type::operator()(const xRegisterInt& to, const xIndirectVoid& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||||
void g1type::operator()(const xRegisterInt &to, int imm) const { _g1_EmitOp(insttype, to, imm); } \
|
void g1type::operator()(const xRegisterInt& to, int imm) const { _g1_EmitOp(insttype, to, imm); } \
|
||||||
void g1type::operator()(const xIndirect64orLess &sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
|
void g1type::operator()(const xIndirect64orLess& sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
|
||||||
|
|
||||||
ImplementGroup1(xImpl_Group1, InstType)
|
ImplementGroup1(xImpl_Group1, InstType)
|
||||||
ImplementGroup1(xImpl_G1Logic, InstType)
|
ImplementGroup1(xImpl_G1Logic, InstType)
|
||||||
ImplementGroup1(xImpl_G1Arith, InstType)
|
ImplementGroup1(xImpl_G1Arith, InstType)
|
||||||
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
|
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
|
||||||
|
|
||||||
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
|
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
|
||||||
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
|
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
|
||||||
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
|
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
|
||||||
|
|
||||||
const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}};
|
const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}};
|
||||||
const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}};
|
const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}};
|
||||||
const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
|
const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
|
||||||
|
|
||||||
const xImpl_Group1 xADC = {G1Type_ADC};
|
const xImpl_Group1 xADC = {G1Type_ADC};
|
||||||
const xImpl_Group1 xSBB = {G1Type_SBB};
|
const xImpl_Group1 xSBB = {G1Type_SBB};
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// Group 2 Instructions - SHR, SHL, etc.
|
// Group 2 Instructions - SHR, SHL, etc.
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
void xImpl_Group2::operator()(const xRegisterInt &to, const xRegisterCL & /* from */) const
|
void xImpl_Group2::operator()(const xRegisterInt& to, const xRegisterCL& /* from */) const
|
||||||
{
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Group2::operator()(const xRegisterInt &to, u8 imm) const
|
void xImpl_Group2::operator()(const xRegisterInt& to, u8 imm) const
|
||||||
{
|
{
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (imm == 1) {
|
if (imm == 1)
|
||||||
// special encoding of 1's
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
// special encoding of 1's
|
||||||
} else {
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
}
|
||||||
xWrite8(imm);
|
else
|
||||||
}
|
{
|
||||||
}
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
||||||
|
xWrite8(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, const xRegisterCL & /* from */) const
|
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, const xRegisterCL& /* from */) const
|
||||||
{
|
{
|
||||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
|
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, u8 imm) const
|
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, u8 imm) const
|
||||||
{
|
{
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (imm == 1) {
|
if (imm == 1)
|
||||||
// special encoding of 1's
|
{
|
||||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
// special encoding of 1's
|
||||||
} else {
|
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
||||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
}
|
||||||
xWrite8(imm);
|
else
|
||||||
}
|
{
|
||||||
}
|
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
||||||
|
xWrite8(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const xImpl_Group2 xROL = {G2Type_ROL};
|
const xImpl_Group2 xROL = {G2Type_ROL};
|
||||||
const xImpl_Group2 xROR = {G2Type_ROR};
|
const xImpl_Group2 xROR = {G2Type_ROR};
|
||||||
const xImpl_Group2 xRCL = {G2Type_RCL};
|
const xImpl_Group2 xRCL = {G2Type_RCL};
|
||||||
const xImpl_Group2 xRCR = {G2Type_RCR};
|
const xImpl_Group2 xRCR = {G2Type_RCR};
|
||||||
const xImpl_Group2 xSHL = {G2Type_SHL};
|
const xImpl_Group2 xSHL = {G2Type_SHL};
|
||||||
const xImpl_Group2 xSHR = {G2Type_SHR};
|
const xImpl_Group2 xSHR = {G2Type_SHR};
|
||||||
const xImpl_Group2 xSAR = {G2Type_SAR};
|
const xImpl_Group2 xSAR = {G2Type_SAR};
|
||||||
|
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// Group 3 Instructions - NOT, NEG, MUL, DIV
|
// Group 3 Instructions - NOT, NEG, MUL, DIV
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
static void _g3_EmitOp(G3Type InstType, const xRegisterInt &from)
|
static void _g3_EmitOp(G3Type InstType, const xRegisterInt& from)
|
||||||
{
|
{
|
||||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess &from)
|
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess& from)
|
||||||
{
|
{
|
||||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Group3::operator()(const xRegisterInt &from) const { _g3_EmitOp(InstType, from); }
|
void xImpl_Group3::operator()(const xRegisterInt& from) const { _g3_EmitOp(InstType, from); }
|
||||||
void xImpl_Group3::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(InstType, from); }
|
void xImpl_Group3::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(InstType, from); }
|
||||||
|
|
||||||
void xImpl_iDiv::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
void xImpl_iDiv::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||||
void xImpl_iDiv::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
void xImpl_iDiv::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||||
|
|
||||||
template <typename SrcType>
|
template <typename SrcType>
|
||||||
static void _imul_ImmStyle(const xRegisterInt ¶m1, const SrcType ¶m2, int imm)
|
static void _imul_ImmStyle(const xRegisterInt& param1, const SrcType& param2, int imm)
|
||||||
{
|
{
|
||||||
pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
|
pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
|
||||||
|
|
||||||
xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize());
|
xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize());
|
||||||
|
|
||||||
if (is_s8(imm))
|
if (is_s8(imm))
|
||||||
xWrite8((u8)imm);
|
xWrite8((u8)imm);
|
||||||
else
|
else
|
||||||
param1.xWriteImm(imm);
|
param1.xWriteImm(imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_iMul::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
void xImpl_iMul::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||||
void xImpl_iMul::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
void xImpl_iMul::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||||
|
|
||||||
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from) const { xOpWrite0F(0xaf, to, from); }
|
void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from) const { xOpWrite0F(0xaf, to, from); }
|
||||||
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &src) const { xOpWrite0F(0xaf, to, src); }
|
void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& src) const { xOpWrite0F(0xaf, to, src); }
|
||||||
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from) const { xOpWrite0F(0x66, 0xaf, to, from); }
|
void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from) const { xOpWrite0F(0x66, 0xaf, to, from); }
|
||||||
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &src) const { xOpWrite0F(0x66, 0xaf, to, src); }
|
void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& src) const { xOpWrite0F(0x66, 0xaf, to, src); }
|
||||||
|
|
||||||
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||||
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||||
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||||
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||||
|
|
||||||
const xImpl_Group3 xNOT = {G3Type_NOT};
|
const xImpl_Group3 xNOT = {G3Type_NOT};
|
||||||
const xImpl_Group3 xNEG = {G3Type_NEG};
|
const xImpl_Group3 xNEG = {G3Type_NEG};
|
||||||
const xImpl_Group3 xUMUL = {G3Type_MUL};
|
const xImpl_Group3 xUMUL = {G3Type_MUL};
|
||||||
const xImpl_Group3 xUDIV = {G3Type_DIV};
|
const xImpl_Group3 xUDIV = {G3Type_DIV};
|
||||||
|
|
||||||
const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
|
const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
|
||||||
const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}};
|
const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}};
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// Group 8 Instructions
|
// Group 8 Instructions
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const
|
void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const
|
||||||
{
|
{
|
||||||
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
|
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
|
||||||
xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset);
|
xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset);
|
||||||
}
|
}
|
||||||
void xImpl_Group8::operator()(const xIndirect64 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
void xImpl_Group8::operator()(const xIndirect64& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||||
void xImpl_Group8::operator()(const xIndirect32 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
void xImpl_Group8::operator()(const xIndirect32& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||||
void xImpl_Group8::operator()(const xIndirect16 &bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); }
|
void xImpl_Group8::operator()(const xIndirect16& bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); }
|
||||||
|
|
||||||
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const
|
void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const
|
||||||
{
|
{
|
||||||
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
|
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Group8::operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const
|
void xImpl_Group8::operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const
|
||||||
{
|
{
|
||||||
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
|
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
const xImpl_Group8 xBT = {G8Type_BT};
|
const xImpl_Group8 xBT = {G8Type_BT};
|
||||||
const xImpl_Group8 xBTR = {G8Type_BTR};
|
const xImpl_Group8 xBTR = {G8Type_BTR};
|
||||||
const xImpl_Group8 xBTS = {G8Type_BTS};
|
const xImpl_Group8 xBTS = {G8Type_BTS};
|
||||||
const xImpl_Group8 xBTC = {G8Type_BTC};
|
const xImpl_Group8 xBTC = {G8Type_BTC};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,19 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
struct xImplBMI_RVM
|
struct xImplBMI_RVM
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u8 MbPrefix;
|
u8 MbPrefix;
|
||||||
u8 Opcode;
|
u8 Opcode;
|
||||||
|
|
||||||
// RVM
|
// RVM
|
||||||
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
|
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
|
||||||
// PDEP Parallel bits deposit
|
// PDEP Parallel bits deposit
|
||||||
// PEXT Parallel bits extract
|
// PEXT Parallel bits extract
|
||||||
// ANDN Logical and not ~x & y
|
// ANDN Logical and not ~x & y
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const;
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// RMV
|
// RMV
|
||||||
|
@ -57,5 +57,5 @@ struct xImplBMI_RVM
|
||||||
void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const;
|
void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const;
|
||||||
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -18,27 +18,27 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// Implementations here cover SHLD and SHRD.
|
// Implementations here cover SHLD and SHRD.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_DowrdShift
|
// xImpl_DowrdShift
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// I use explicit method declarations here instead of templates, in order to provide
|
// I use explicit method declarations here instead of templates, in order to provide
|
||||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
||||||
//
|
//
|
||||||
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
||||||
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
||||||
//
|
//
|
||||||
struct xImpl_DwordShift
|
struct xImpl_DwordShift
|
||||||
{
|
{
|
||||||
u16 OpcodeBase;
|
u16 OpcodeBase;
|
||||||
|
|
||||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, const xRegisterCL &clreg) const;
|
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||||
|
|
||||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, u8 shiftcnt) const;
|
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, const xRegisterCL &clreg) const;
|
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||||
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, u8 shiftcnt) const;
|
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -18,32 +18,33 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G1Type {
|
enum G1Type
|
||||||
G1Type_ADD = 0,
|
{
|
||||||
G1Type_OR,
|
G1Type_ADD = 0,
|
||||||
G1Type_ADC,
|
G1Type_OR,
|
||||||
G1Type_SBB,
|
G1Type_ADC,
|
||||||
G1Type_AND,
|
G1Type_SBB,
|
||||||
G1Type_SUB,
|
G1Type_AND,
|
||||||
G1Type_XOR,
|
G1Type_SUB,
|
||||||
G1Type_CMP
|
G1Type_XOR,
|
||||||
};
|
G1Type_CMP
|
||||||
|
};
|
||||||
|
|
||||||
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from);
|
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_Group1
|
// xImpl_Group1
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImpl_Group1
|
struct xImpl_Group1
|
||||||
{
|
{
|
||||||
G1Type InstType;
|
G1Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xRegisterInt &to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -79,64 +80,64 @@ struct xImpl_Group1
|
||||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
||||||
// Note: ANDN [AndNot] is handled below separately.
|
// Note: ANDN [AndNot] is handled below separately.
|
||||||
//
|
//
|
||||||
struct xImpl_G1Logic
|
struct xImpl_G1Logic
|
||||||
{
|
{
|
||||||
G1Type InstType;
|
G1Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xRegisterInt &to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
|
|
||||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||||
|
|
||||||
xImplSimd_DestRegSSE PS; // packed single precision
|
xImplSimd_DestRegSSE PS; // packed single precision
|
||||||
xImplSimd_DestRegSSE PD; // packed double precision
|
xImplSimd_DestRegSSE PD; // packed double precision
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
||||||
//
|
//
|
||||||
struct xImpl_G1Arith
|
struct xImpl_G1Arith
|
||||||
{
|
{
|
||||||
G1Type InstType;
|
G1Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xRegisterInt &to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
|
|
||||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||||
|
|
||||||
xImplSimd_DestRegSSE PS; // packed single precision
|
xImplSimd_DestRegSSE PS; // packed single precision
|
||||||
xImplSimd_DestRegSSE PD; // packed double precision
|
xImplSimd_DestRegSSE PD; // packed double precision
|
||||||
xImplSimd_DestRegSSE SS; // scalar single precision
|
xImplSimd_DestRegSSE SS; // scalar single precision
|
||||||
xImplSimd_DestRegSSE SD; // scalar double precision
|
xImplSimd_DestRegSSE SD; // scalar double precision
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct xImpl_G1Compare
|
struct xImpl_G1Compare
|
||||||
{
|
{
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xRegisterInt &to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
|
|
||||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||||
|
|
||||||
xImplSimd_DestSSE_CmpImm PS;
|
xImplSimd_DestSSE_CmpImm PS;
|
||||||
xImplSimd_DestSSE_CmpImm PD;
|
xImplSimd_DestSSE_CmpImm PD;
|
||||||
xImplSimd_DestSSE_CmpImm SS;
|
xImplSimd_DestSSE_CmpImm SS;
|
||||||
xImplSimd_DestSSE_CmpImm SD;
|
xImplSimd_DestSSE_CmpImm SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -18,32 +18,33 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G2Type {
|
enum G2Type
|
||||||
G2Type_ROL = 0,
|
{
|
||||||
G2Type_ROR,
|
G2Type_ROL = 0,
|
||||||
G2Type_RCL,
|
G2Type_ROR,
|
||||||
G2Type_RCR,
|
G2Type_RCL,
|
||||||
G2Type_SHL,
|
G2Type_RCR,
|
||||||
G2Type_SHR,
|
G2Type_SHL,
|
||||||
G2Type_Unused,
|
G2Type_SHR,
|
||||||
G2Type_SAR
|
G2Type_Unused,
|
||||||
};
|
G2Type_SAR
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_Group2
|
// xImpl_Group2
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
||||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
||||||
// This is a safe optimization since any zero-value shift does not affect any flags.
|
// This is a safe optimization since any zero-value shift does not affect any flags.
|
||||||
//
|
//
|
||||||
struct xImpl_Group2
|
struct xImpl_Group2
|
||||||
{
|
{
|
||||||
G2Type InstType;
|
G2Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to, const xRegisterCL &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterCL& from) const;
|
||||||
void operator()(const xIndirect64orLess &to, const xRegisterCL &from) const;
|
void operator()(const xIndirect64orLess& to, const xRegisterCL& from) const;
|
||||||
void operator()(const xRegisterInt &to, u8 imm) const;
|
void operator()(const xRegisterInt& to, u8 imm) const;
|
||||||
void operator()(const xIndirect64orLess &to, u8 imm) const;
|
void operator()(const xIndirect64orLess& to, u8 imm) const;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -57,6 +58,6 @@ struct xImpl_Group2
|
||||||
_DoI_helpermess( *this, to, from );
|
_DoI_helpermess( *this, to, from );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -18,24 +18,25 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G3Type {
|
enum G3Type
|
||||||
G3Type_NOT = 2,
|
{
|
||||||
G3Type_NEG = 3,
|
G3Type_NOT = 2,
|
||||||
G3Type_MUL = 4,
|
G3Type_NEG = 3,
|
||||||
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
|
G3Type_MUL = 4,
|
||||||
G3Type_DIV = 6,
|
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
|
||||||
G3Type_iDIV = 7
|
G3Type_DIV = 6,
|
||||||
};
|
G3Type_iDIV = 7
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_Group3
|
// xImpl_Group3
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImpl_Group3
|
struct xImpl_Group3
|
||||||
{
|
{
|
||||||
G3Type InstType;
|
G3Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirect64orLess &from) const;
|
void operator()(const xIndirect64orLess& from) const;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
template< typename T >
|
template< typename T >
|
||||||
|
@ -44,65 +45,65 @@ struct xImpl_Group3
|
||||||
_DoI_helpermess( *this, from );
|
_DoI_helpermess( *this, from );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_MulDivBase
|
// xImpl_MulDivBase
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
||||||
//
|
//
|
||||||
struct xImpl_MulDivBase
|
struct xImpl_MulDivBase
|
||||||
{
|
{
|
||||||
G3Type InstType;
|
G3Type InstType;
|
||||||
u16 OpcodeSSE;
|
u16 OpcodeSSE;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirect64orLess &from) const;
|
void operator()(const xIndirect64orLess& from) const;
|
||||||
|
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE PD;
|
const xImplSimd_DestRegSSE PD;
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_iDiv
|
// xImpl_iDiv
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImpl_iDiv
|
struct xImpl_iDiv
|
||||||
{
|
{
|
||||||
void operator()(const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirect64orLess &from) const;
|
void operator()(const xIndirect64orLess& from) const;
|
||||||
|
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE PD;
|
const xImplSimd_DestRegSSE PD;
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_iMul
|
// xImpl_iMul
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
struct xImpl_iMul
|
struct xImpl_iMul
|
||||||
{
|
{
|
||||||
void operator()(const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirect64orLess &from) const;
|
void operator()(const xIndirect64orLess& from) const;
|
||||||
|
|
||||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||||
|
|
||||||
void operator()(const xRegister32 &to, const xRegister32 &from) const;
|
void operator()(const xRegister32& to, const xRegister32& from) const;
|
||||||
void operator()(const xRegister32 &to, const xIndirectVoid &src) const;
|
void operator()(const xRegister32& to, const xIndirectVoid& src) const;
|
||||||
void operator()(const xRegister16 &to, const xRegister16 &from) const;
|
void operator()(const xRegister16& to, const xRegister16& from) const;
|
||||||
void operator()(const xRegister16 &to, const xIndirectVoid &src) const;
|
void operator()(const xRegister16& to, const xIndirectVoid& src) const;
|
||||||
|
|
||||||
void operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const;
|
void operator()(const xRegister32& to, const xRegister32& from, s32 imm) const;
|
||||||
void operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const;
|
void operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const;
|
||||||
void operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const;
|
void operator()(const xRegister16& to, const xRegister16& from, s16 imm) const;
|
||||||
void operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const;
|
void operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const;
|
||||||
|
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE PD;
|
const xImplSimd_DestRegSSE PD;
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -21,15 +21,15 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_IncDec
|
// xImpl_IncDec
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImpl_IncDec
|
struct xImpl_IncDec
|
||||||
{
|
{
|
||||||
bool isDec;
|
bool isDec;
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to) const;
|
void operator()(const xRegisterInt& to) const;
|
||||||
void operator()(const xIndirect64orLess &to) const;
|
void operator()(const xIndirect64orLess& to) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -20,74 +20,75 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
extern void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward);
|
extern void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct xImpl_JmpCall
|
struct xImpl_JmpCall
|
||||||
{
|
{
|
||||||
bool isJmp;
|
bool isJmp;
|
||||||
|
|
||||||
void operator()(const xAddressReg &absreg) const;
|
void operator()(const xAddressReg& absreg) const;
|
||||||
void operator()(const xIndirectNative &src) const;
|
void operator()(const xIndirectNative& src) const;
|
||||||
|
|
||||||
// Special form for calling functions. This form automatically resolves the
|
// Special form for calling functions. This form automatically resolves the
|
||||||
// correct displacement based on the size of the instruction being generated.
|
// correct displacement based on the size of the instruction being generated.
|
||||||
void operator()(void *func) const
|
void operator()(void* func) const
|
||||||
{
|
{
|
||||||
if (isJmp)
|
if (isJmp)
|
||||||
xJccKnownTarget(Jcc_Unconditional, (void *)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
||||||
else {
|
else
|
||||||
// calls are relative to the instruction after this one, and length is
|
{
|
||||||
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
// calls are relative to the instruction after this one, and length is
|
||||||
|
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
||||||
|
|
||||||
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
|
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
|
||||||
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
|
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
|
||||||
xWrite8(0xe8);
|
xWrite8(0xe8);
|
||||||
xWrite32(dest);
|
xWrite32(dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// yes it is awful. Due to template code is in a header with a nice circular dep.
|
// yes it is awful. Due to template code is in a header with a nice circular dep.
|
||||||
extern const xImpl_Mov xMOV;
|
extern const xImpl_Mov xMOV;
|
||||||
extern const xImpl_JmpCall xCALL;
|
extern const xImpl_JmpCall xCALL;
|
||||||
|
|
||||||
struct xImpl_FastCall
|
struct xImpl_FastCall
|
||||||
{
|
{
|
||||||
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
|
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
|
||||||
// some registers. But I think it is enough to handle the first call.
|
// some registers. But I think it is enough to handle the first call.
|
||||||
|
|
||||||
void operator()(void *f, const xRegister32 &a1 = xEmptyReg, const xRegister32 &a2 = xEmptyReg) const;
|
void operator()(void* f, const xRegister32& a1 = xEmptyReg, const xRegister32& a2 = xEmptyReg) const;
|
||||||
|
|
||||||
void operator()(void *f, u32 a1, const xRegister32 &a2) const;
|
void operator()(void* f, u32 a1, const xRegister32& a2) const;
|
||||||
void operator()(void *f, const xIndirect32 &a1) const;
|
void operator()(void* f, const xIndirect32& a1) const;
|
||||||
void operator()(void *f, u32 a1, u32 a2) const;
|
void operator()(void* f, u32 a1, u32 a2) const;
|
||||||
void operator()(void *f, void *a1) const;
|
void operator()(void* f, void* a1) const;
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
void operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2 = xEmptyReg) const;
|
void operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
|
||||||
void operator()(void *f, u32 a1, const xRegisterLong &a2) const;
|
void operator()(void* f, u32 a1, const xRegisterLong& a2) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
__fi void operator()(T *func, u32 a1, const xRegisterLong &a2 = xEmptyReg) const
|
__fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
|
||||||
{
|
{
|
||||||
(*this)((void *)func, a1, a2);
|
(*this)((void*)func, a1, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
__fi void operator()(T *func, const xIndirect32 &a1) const
|
__fi void operator()(T* func, const xIndirect32& a1) const
|
||||||
{
|
{
|
||||||
(*this)((void*)func, a1);
|
(*this)((void*)func, a1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
__fi void operator()(T *func, u32 a1, u32 a2) const
|
__fi void operator()(T* func, u32 a1, u32 a2) const
|
||||||
{
|
{
|
||||||
(*this)((void*)func, a1, a2);
|
(*this)((void*)func, a1, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const xIndirectNative &f, const xRegisterLong &a1 = xEmptyReg, const xRegisterLong &a2 = xEmptyReg) const;
|
void operator()(const xIndirectNative& f, const xRegisterLong& a1 = xEmptyReg, const xRegisterLong& a2 = xEmptyReg) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -21,20 +21,20 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// MovImplAll
|
// MovImplAll
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
||||||
//
|
//
|
||||||
struct xImpl_Mov
|
struct xImpl_Mov
|
||||||
{
|
{
|
||||||
xImpl_Mov() {} // Satisfy GCC's whims.
|
xImpl_Mov() {} // Satisfy GCC's whims.
|
||||||
|
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirectVoid &dest, const xRegisterInt &from) const;
|
void operator()(const xIndirectVoid& dest, const xRegisterInt& from) const;
|
||||||
void operator()(const xRegisterInt &to, const xIndirectVoid &src) const;
|
void operator()(const xRegisterInt& to, const xIndirectVoid& src) const;
|
||||||
void operator()(const xIndirect64orLess &dest, sptr imm) const;
|
void operator()(const xIndirect64orLess& dest, sptr imm) const;
|
||||||
void operator()(const xRegisterInt &to, sptr imm, bool preserve_flags = false) const;
|
void operator()(const xRegisterInt& to, sptr imm, bool preserve_flags = false) const;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||||
|
@ -68,73 +68,73 @@ struct xImpl_Mov
|
||||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||||
}*/
|
}*/
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_MovImm64
|
// xImpl_MovImm64
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Mov with 64-bit immediates (only available on 64-bit platforms)
|
// Mov with 64-bit immediates (only available on 64-bit platforms)
|
||||||
//
|
//
|
||||||
struct xImpl_MovImm64
|
struct xImpl_MovImm64
|
||||||
{
|
{
|
||||||
xImpl_MovImm64() {} // Satisfy GCC's whims.
|
xImpl_MovImm64() {} // Satisfy GCC's whims.
|
||||||
|
|
||||||
void operator()(const xRegister64 &to, s64 imm, bool preserve_flags = false) const;
|
void operator()(const xRegister64& to, s64 imm, bool preserve_flags = false) const;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_CMov
|
// xImpl_CMov
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
||||||
// SETcc !! [more glory, less lack!]
|
// SETcc !! [more glory, less lack!]
|
||||||
//
|
//
|
||||||
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
||||||
// realize that it cannot load immediate values into registers. -_-
|
// realize that it cannot load immediate values into registers. -_-
|
||||||
//
|
//
|
||||||
// I use explicit method declarations here instead of templates, in order to provide
|
// I use explicit method declarations here instead of templates, in order to provide
|
||||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
||||||
//
|
//
|
||||||
|
|
||||||
struct xImpl_CMov
|
struct xImpl_CMov
|
||||||
{
|
{
|
||||||
JccComparisonType ccType;
|
JccComparisonType ccType;
|
||||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
|
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||||
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
|
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||||
|
|
||||||
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
||||||
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xImpl_Set
|
struct xImpl_Set
|
||||||
{
|
{
|
||||||
JccComparisonType ccType;
|
JccComparisonType ccType;
|
||||||
|
|
||||||
void operator()(const xRegister8 &to) const;
|
void operator()(const xRegister8& to) const;
|
||||||
void operator()(const xIndirect8 &dest) const;
|
void operator()(const xIndirect8& dest) const;
|
||||||
|
|
||||||
//void operator()( const xDirectOrIndirect8& dest ) const;
|
//void operator()( const xDirectOrIndirect8& dest ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_MovExtend
|
// xImpl_MovExtend
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||||
//
|
//
|
||||||
struct xImpl_MovExtend
|
struct xImpl_MovExtend
|
||||||
{
|
{
|
||||||
bool SignExtend;
|
bool SignExtend;
|
||||||
|
|
||||||
void operator()(const xRegister16or32or64 &to, const xRegister8 &from) const;
|
void operator()(const xRegister16or32or64& to, const xRegister8& from) const;
|
||||||
void operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const;
|
void operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const;
|
||||||
void operator()(const xRegister32or64 &to, const xRegister16 &from) const;
|
void operator()(const xRegister32or64& to, const xRegister16& from) const;
|
||||||
void operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const;
|
void operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const;
|
||||||
|
|
||||||
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
||||||
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
||||||
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -18,299 +18,299 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// _SimdShiftHelper
|
// _SimdShiftHelper
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct _SimdShiftHelper
|
struct _SimdShiftHelper
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
u16 OpcodeImm;
|
u16 OpcodeImm;
|
||||||
u8 Modcode;
|
u8 Modcode;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, u8 imm8) const;
|
void operator()(const xRegisterSSE& to, u8 imm8) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ
|
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Used for PSRA, which lacks the Q form.
|
// Used for PSRA, which lacks the Q form.
|
||||||
//
|
//
|
||||||
struct xImplSimd_ShiftWithoutQ
|
struct xImplSimd_ShiftWithoutQ
|
||||||
{
|
{
|
||||||
const _SimdShiftHelper W;
|
const _SimdShiftHelper W;
|
||||||
const _SimdShiftHelper D;
|
const _SimdShiftHelper D;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implements PSRL and PSLL
|
// Implements PSRL and PSLL
|
||||||
//
|
//
|
||||||
struct xImplSimd_Shift
|
struct xImplSimd_Shift
|
||||||
{
|
{
|
||||||
const _SimdShiftHelper W;
|
const _SimdShiftHelper W;
|
||||||
const _SimdShiftHelper D;
|
const _SimdShiftHelper D;
|
||||||
const _SimdShiftHelper Q;
|
const _SimdShiftHelper Q;
|
||||||
|
|
||||||
void DQ(const xRegisterSSE &to, u8 imm8) const;
|
void DQ(const xRegisterSSE& to, u8 imm8) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_AddSub
|
struct xImplSimd_AddSub
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegEither B;
|
const xImplSimd_DestRegEither B;
|
||||||
const xImplSimd_DestRegEither W;
|
const xImplSimd_DestRegEither W;
|
||||||
const xImplSimd_DestRegEither D;
|
const xImplSimd_DestRegEither D;
|
||||||
const xImplSimd_DestRegEither Q;
|
const xImplSimd_DestRegEither Q;
|
||||||
|
|
||||||
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
|
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
|
||||||
const xImplSimd_DestRegEither SB;
|
const xImplSimd_DestRegEither SB;
|
||||||
|
|
||||||
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
|
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
|
||||||
const xImplSimd_DestRegEither SW;
|
const xImplSimd_DestRegEither SW;
|
||||||
|
|
||||||
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
|
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
|
||||||
const xImplSimd_DestRegEither USB;
|
const xImplSimd_DestRegEither USB;
|
||||||
|
|
||||||
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
|
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
|
||||||
const xImplSimd_DestRegEither USW;
|
const xImplSimd_DestRegEither USW;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_PMul
|
struct xImplSimd_PMul
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegEither LW;
|
const xImplSimd_DestRegEither LW;
|
||||||
const xImplSimd_DestRegEither HW;
|
const xImplSimd_DestRegEither HW;
|
||||||
const xImplSimd_DestRegEither HUW;
|
const xImplSimd_DestRegEither HUW;
|
||||||
const xImplSimd_DestRegEither UDQ;
|
const xImplSimd_DestRegEither UDQ;
|
||||||
|
|
||||||
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
|
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
|
||||||
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
|
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
|
||||||
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant
|
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant
|
||||||
// bits. Rounding is always performed by adding 1 to the least significant bit of the
|
// bits. Rounding is always performed by adding 1 to the least significant bit of the
|
||||||
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits
|
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits
|
||||||
// immediately to the right of the most significant bit of each 18-bit intermediate
|
// immediately to the right of the most significant bit of each 18-bit intermediate
|
||||||
// result and packed to the destination operand.
|
// result and packed to the destination operand.
|
||||||
//
|
//
|
||||||
// Both operands can be MMX or XMM registers. Source can be register or memory.
|
// Both operands can be MMX or XMM registers. Source can be register or memory.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegEither HRSW;
|
const xImplSimd_DestRegEither HRSW;
|
||||||
|
|
||||||
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
|
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
|
||||||
// the low 32 bits of each product in xmm1.
|
// the low 32 bits of each product in xmm1.
|
||||||
const xImplSimd_DestRegSSE LD;
|
const xImplSimd_DestRegSSE LD;
|
||||||
|
|
||||||
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
|
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
|
||||||
const xImplSimd_DestRegSSE DQ;
|
const xImplSimd_DestRegSSE DQ;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
|
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
|
||||||
//
|
//
|
||||||
struct xImplSimd_rSqrt
|
struct xImplSimd_rSqrt
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// SQRT has PS/SS/SD forms, but not the PD form.
|
// SQRT has PS/SS/SD forms, but not the PD form.
|
||||||
//
|
//
|
||||||
struct xImplSimd_Sqrt
|
struct xImplSimd_Sqrt
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_AndNot
|
struct xImplSimd_AndNot
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
const xImplSimd_DestRegSSE PD;
|
const xImplSimd_DestRegSSE PD;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Packed absolute value. [sSSE3 only]
|
// Packed absolute value. [sSSE3 only]
|
||||||
//
|
//
|
||||||
struct xImplSimd_PAbsolute
|
struct xImplSimd_PAbsolute
|
||||||
{
|
{
|
||||||
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
|
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
|
||||||
// in dest, as UNSIGNED.
|
// in dest, as UNSIGNED.
|
||||||
const xImplSimd_DestRegEither B;
|
const xImplSimd_DestRegEither B;
|
||||||
|
|
||||||
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
|
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
|
||||||
// in dest, as UNSIGNED.
|
// in dest, as UNSIGNED.
|
||||||
const xImplSimd_DestRegEither W;
|
const xImplSimd_DestRegEither W;
|
||||||
|
|
||||||
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
|
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
|
||||||
// result in dest, as UNSIGNED.
|
// result in dest, as UNSIGNED.
|
||||||
const xImplSimd_DestRegEither D;
|
const xImplSimd_DestRegEither D;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
|
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
|
||||||
// corresponding sign in src.
|
// corresponding sign in src.
|
||||||
//
|
//
|
||||||
struct xImplSimd_PSign
|
struct xImplSimd_PSign
|
||||||
{
|
{
|
||||||
// [sSSE-3] negates each byte element of dest if the signed integer value of the
|
// [sSSE-3] negates each byte element of dest if the signed integer value of the
|
||||||
// corresponding data element in src is less than zero. If the signed integer value
|
// corresponding data element in src is less than zero. If the signed integer value
|
||||||
// of a data element in src is positive, the corresponding data element in dest is
|
// of a data element in src is positive, the corresponding data element in dest is
|
||||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||||
// dest is set to zero.
|
// dest is set to zero.
|
||||||
const xImplSimd_DestRegEither B;
|
const xImplSimd_DestRegEither B;
|
||||||
|
|
||||||
// [sSSE-3] negates each word element of dest if the signed integer value of the
|
// [sSSE-3] negates each word element of dest if the signed integer value of the
|
||||||
// corresponding data element in src is less than zero. If the signed integer value
|
// corresponding data element in src is less than zero. If the signed integer value
|
||||||
// of a data element in src is positive, the corresponding data element in dest is
|
// of a data element in src is positive, the corresponding data element in dest is
|
||||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||||
// dest is set to zero.
|
// dest is set to zero.
|
||||||
const xImplSimd_DestRegEither W;
|
const xImplSimd_DestRegEither W;
|
||||||
|
|
||||||
// [sSSE-3] negates each doubleword element of dest if the signed integer value
|
// [sSSE-3] negates each doubleword element of dest if the signed integer value
|
||||||
// of the corresponding data element in src is less than zero. If the signed integer
|
// of the corresponding data element in src is less than zero. If the signed integer
|
||||||
// value of a data element in src is positive, the corresponding data element in dest
|
// value of a data element in src is positive, the corresponding data element in dest
|
||||||
// is unchanged. If a data element in src is zero, the corresponding data element in
|
// is unchanged. If a data element in src is zero, the corresponding data element in
|
||||||
// dest is set to zero.
|
// dest is set to zero.
|
||||||
const xImplSimd_DestRegEither D;
|
const xImplSimd_DestRegEither D;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Packed Multiply and Add!!
|
// Packed Multiply and Add!!
|
||||||
//
|
//
|
||||||
struct xImplSimd_PMultAdd
|
struct xImplSimd_PMultAdd
|
||||||
{
|
{
|
||||||
// Multiplies the individual signed words of dest by the corresponding signed words
|
// Multiplies the individual signed words of dest by the corresponding signed words
|
||||||
// of src, producing temporary signed, doubleword results. The adjacent doubleword
|
// of src, producing temporary signed, doubleword results. The adjacent doubleword
|
||||||
// results are then summed and stored in the destination operand.
|
// results are then summed and stored in the destination operand.
|
||||||
//
|
//
|
||||||
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
|
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
|
||||||
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
|
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
|
||||||
// [.. repeat in the case of XMM src/dest operands ..]
|
// [.. repeat in the case of XMM src/dest operands ..]
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegEither WD;
|
const xImplSimd_DestRegEither WD;
|
||||||
|
|
||||||
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
|
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
|
||||||
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
|
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
|
||||||
// pair of signed words is added and the saturated result is packed to dest.
|
// pair of signed words is added and the saturated result is packed to dest.
|
||||||
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
|
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
|
||||||
// and the intermediate signed word result is added with the corresponding
|
// and the intermediate signed word result is added with the corresponding
|
||||||
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
|
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
|
||||||
// the sign-saturated result is stored in the lowest word of dest (bits 15-0).
|
// the sign-saturated result is stored in the lowest word of dest (bits 15-0).
|
||||||
// The same operation is performed on the other pairs of adjacent bytes.
|
// The same operation is performed on the other pairs of adjacent bytes.
|
||||||
//
|
//
|
||||||
// In Coder Speak:
|
// In Coder Speak:
|
||||||
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
|
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
|
||||||
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
|
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
|
||||||
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
|
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegEither UBSW;
|
const xImplSimd_DestRegEither UBSW;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Packed Horizontal Add [SSE3 only]
|
// Packed Horizontal Add [SSE3 only]
|
||||||
//
|
//
|
||||||
struct xImplSimd_HorizAdd
|
struct xImplSimd_HorizAdd
|
||||||
{
|
{
|
||||||
// [SSE-3] Horizontal Add of Packed Data. A three step process:
|
// [SSE-3] Horizontal Add of Packed Data. A three step process:
|
||||||
// * Adds the single-precision floating-point values in the first and second dwords of
|
// * Adds the single-precision floating-point values in the first and second dwords of
|
||||||
// dest and stores the result in the first dword of dest.
|
// dest and stores the result in the first dword of dest.
|
||||||
// * Adds single-precision floating-point values in the third and fourth dword of dest
|
// * Adds single-precision floating-point values in the third and fourth dword of dest
|
||||||
// stores the result in the second dword of dest.
|
// stores the result in the second dword of dest.
|
||||||
// * Adds single-precision floating-point values in the first and second dword of *src*
|
// * Adds single-precision floating-point values in the first and second dword of *src*
|
||||||
// and stores the result in the third dword of dest.
|
// and stores the result in the third dword of dest.
|
||||||
const xImplSimd_DestRegSSE PS;
|
const xImplSimd_DestRegSSE PS;
|
||||||
|
|
||||||
// [SSE-3] Horizontal Add of Packed Data. A two step process:
|
// [SSE-3] Horizontal Add of Packed Data. A two step process:
|
||||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||||
// dest and stores the result in the low quadword of dest.
|
// dest and stores the result in the low quadword of dest.
|
||||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||||
// *src* stores the result in the high quadword of dest.
|
// *src* stores the result in the high quadword of dest.
|
||||||
const xImplSimd_DestRegSSE PD;
|
const xImplSimd_DestRegSSE PD;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// DotProduct calculation (SSE4.1 only!)
|
// DotProduct calculation (SSE4.1 only!)
|
||||||
//
|
//
|
||||||
struct xImplSimd_DotProduct
|
struct xImplSimd_DotProduct
|
||||||
{
|
{
|
||||||
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point
|
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point
|
||||||
// values in dest with the packed single-precision floats in src depending on a
|
// values in dest with the packed single-precision floats in src depending on a
|
||||||
// mask extracted from the high 4 bits of the immediate byte. If a condition mask
|
// mask extracted from the high 4 bits of the immediate byte. If a condition mask
|
||||||
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
|
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
|
||||||
// of 0.0. The four resulting single-precision values are summed into an inter-
|
// of 0.0. The four resulting single-precision values are summed into an inter-
|
||||||
// mediate result.
|
// mediate result.
|
||||||
//
|
//
|
||||||
// The intermediate result is conditionally broadcasted to the destination using a
|
// The intermediate result is conditionally broadcasted to the destination using a
|
||||||
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
|
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
|
||||||
// mask bit is 1, the intermediate result is copied to the corresponding dword
|
// mask bit is 1, the intermediate result is copied to the corresponding dword
|
||||||
// element in dest. If a broadcast mask bit is zero, the corresponding element in
|
// element in dest. If a broadcast mask bit is zero, the corresponding element in
|
||||||
// the destination is set to zero.
|
// the destination is set to zero.
|
||||||
//
|
//
|
||||||
xImplSimd_DestRegImmSSE PS;
|
xImplSimd_DestRegImmSSE PS;
|
||||||
|
|
||||||
// [SSE-4.1]
|
// [SSE-4.1]
|
||||||
xImplSimd_DestRegImmSSE PD;
|
xImplSimd_DestRegImmSSE PD;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
|
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
|
||||||
// (SSE4.1 only!)
|
// (SSE4.1 only!)
|
||||||
struct xImplSimd_Round
|
struct xImplSimd_Round
|
||||||
{
|
{
|
||||||
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
|
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
|
||||||
//
|
//
|
||||||
// Imm8 specifies control fields for the rounding operation:
|
// Imm8 specifies control fields for the rounding operation:
|
||||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||||
//
|
//
|
||||||
// Rounding Mode Reference:
|
// Rounding Mode Reference:
|
||||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegImmSSE PS;
|
const xImplSimd_DestRegImmSSE PS;
|
||||||
|
|
||||||
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
|
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
|
||||||
//
|
//
|
||||||
// Imm8 specifies control fields for the rounding operation:
|
// Imm8 specifies control fields for the rounding operation:
|
||||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||||
//
|
//
|
||||||
// Rounding Mode Reference:
|
// Rounding Mode Reference:
|
||||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegImmSSE PD;
|
const xImplSimd_DestRegImmSSE PD;
|
||||||
|
|
||||||
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
|
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
|
||||||
//
|
//
|
||||||
// Imm8 specifies control fields for the rounding operation:
|
// Imm8 specifies control fields for the rounding operation:
|
||||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||||
//
|
//
|
||||||
// Rounding Mode Reference:
|
// Rounding Mode Reference:
|
||||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegImmSSE SS;
|
const xImplSimd_DestRegImmSSE SS;
|
||||||
|
|
||||||
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
|
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
|
||||||
//
|
//
|
||||||
// Imm8 specifies control fields for the rounding operation:
|
// Imm8 specifies control fields for the rounding operation:
|
||||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||||
//
|
//
|
||||||
// Rounding Mode Reference:
|
// Rounding Mode Reference:
|
||||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegImmSSE SD;
|
const xImplSimd_DestRegImmSSE SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
|
@ -18,106 +18,106 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
struct xImplSimd_MinMax
|
struct xImplSimd_MinMax
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegSSE PS; // packed single precision
|
const xImplSimd_DestRegSSE PS; // packed single precision
|
||||||
const xImplSimd_DestRegSSE PD; // packed double precision
|
const xImplSimd_DestRegSSE PD; // packed double precision
|
||||||
const xImplSimd_DestRegSSE SS; // scalar single precision
|
const xImplSimd_DestRegSSE SS; // scalar single precision
|
||||||
const xImplSimd_DestRegSSE SD; // scalar double precision
|
const xImplSimd_DestRegSSE SD; // scalar double precision
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_Compare
|
struct xImplSimd_Compare
|
||||||
{
|
{
|
||||||
SSE2_ComparisonType CType;
|
SSE2_ComparisonType CType;
|
||||||
|
|
||||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
|
|
||||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
|
|
||||||
void SS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void SS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void SS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void SS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
|
|
||||||
void SD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void SD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void SD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void SD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
|
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
|
||||||
//
|
//
|
||||||
struct xImplSimd_COMI
|
struct xImplSimd_COMI
|
||||||
{
|
{
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_PCompare
|
struct xImplSimd_PCompare
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Compare packed bytes for equality.
|
// Compare packed bytes for equality.
|
||||||
// If a data element in dest is equal to the corresponding date element src, the
|
// If a data element in dest is equal to the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither EQB;
|
const xImplSimd_DestRegEither EQB;
|
||||||
|
|
||||||
// Compare packed words for equality.
|
// Compare packed words for equality.
|
||||||
// If a data element in dest is equal to the corresponding date element src, the
|
// If a data element in dest is equal to the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither EQW;
|
const xImplSimd_DestRegEither EQW;
|
||||||
|
|
||||||
// Compare packed doublewords [32-bits] for equality.
|
// Compare packed doublewords [32-bits] for equality.
|
||||||
// If a data element in dest is equal to the corresponding date element src, the
|
// If a data element in dest is equal to the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither EQD;
|
const xImplSimd_DestRegEither EQD;
|
||||||
|
|
||||||
// Compare packed signed bytes for greater than.
|
// Compare packed signed bytes for greater than.
|
||||||
// If a data element in dest is greater than the corresponding date element src, the
|
// If a data element in dest is greater than the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither GTB;
|
const xImplSimd_DestRegEither GTB;
|
||||||
|
|
||||||
// Compare packed signed words for greater than.
|
// Compare packed signed words for greater than.
|
||||||
// If a data element in dest is greater than the corresponding date element src, the
|
// If a data element in dest is greater than the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither GTW;
|
const xImplSimd_DestRegEither GTW;
|
||||||
|
|
||||||
// Compare packed signed doublewords [32-bits] for greater than.
|
// Compare packed signed doublewords [32-bits] for greater than.
|
||||||
// If a data element in dest is greater than the corresponding date element src, the
|
// If a data element in dest is greater than the corresponding date element src, the
|
||||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||||
const xImplSimd_DestRegEither GTD;
|
const xImplSimd_DestRegEither GTD;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
struct xImplSimd_PMinMax
|
struct xImplSimd_PMinMax
|
||||||
{
|
{
|
||||||
// Compare packed unsigned byte integers in dest to src and store packed min/max
|
// Compare packed unsigned byte integers in dest to src and store packed min/max
|
||||||
// values in dest.
|
// values in dest.
|
||||||
const xImplSimd_DestRegEither UB;
|
const xImplSimd_DestRegEither UB;
|
||||||
|
|
||||||
// Compare packed signed word integers in dest to src and store packed min/max
|
// Compare packed signed word integers in dest to src and store packed min/max
|
||||||
// values in dest.
|
// values in dest.
|
||||||
const xImplSimd_DestRegEither SW;
|
const xImplSimd_DestRegEither SW;
|
||||||
|
|
||||||
// [SSE-4.1] Compare packed signed byte integers in dest to src and store
|
// [SSE-4.1] Compare packed signed byte integers in dest to src and store
|
||||||
// packed min/max values in dest. (SSE operands only)
|
// packed min/max values in dest. (SSE operands only)
|
||||||
const xImplSimd_DestRegSSE SB;
|
const xImplSimd_DestRegSSE SB;
|
||||||
|
|
||||||
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
|
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
|
||||||
// packed min/max values in dest. (SSE operands only)
|
// packed min/max values in dest. (SSE operands only)
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
|
|
||||||
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store
|
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store
|
||||||
// packed min/max values in dest. (SSE operands only)
|
// packed min/max values in dest. (SSE operands only)
|
||||||
const xImplSimd_DestRegSSE UW;
|
const xImplSimd_DestRegSSE UW;
|
||||||
|
|
||||||
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
|
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
|
||||||
// packed min/max values in dest. (SSE operands only)
|
// packed min/max values in dest. (SSE operands only)
|
||||||
const xImplSimd_DestRegSSE UD;
|
const xImplSimd_DestRegSSE UD;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace x86Emitter
|
} // end namespace x86Emitter
|
||||||
|
|
|
@ -18,56 +18,56 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// xImpl_SIMD Types (template free!)
|
// xImpl_SIMD Types (template free!)
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
||||||
// like ANDPS/ANDPD
|
// like ANDPS/ANDPD
|
||||||
//
|
//
|
||||||
struct xImplSimd_DestRegSSE
|
struct xImplSimd_DestRegSSE
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
|
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
|
||||||
// (PSHUFD / PSHUFHW / etc).
|
// (PSHUFD / PSHUFHW / etc).
|
||||||
//
|
//
|
||||||
struct xImplSimd_DestRegImmSSE
|
struct xImplSimd_DestRegImmSSE
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, u8 imm) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, u8 imm) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xImplSimd_DestSSE_CmpImm
|
struct xImplSimd_DestSSE_CmpImm
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, SSE2_ComparisonType imm) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, SSE2_ComparisonType imm) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, SSE2_ComparisonType imm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// For implementing SSE operations that have reg,reg/rm forms only,
|
// For implementing SSE operations that have reg,reg/rm forms only,
|
||||||
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
|
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
|
||||||
//
|
//
|
||||||
struct xImplSimd_DestRegEither
|
struct xImplSimd_DestRegEither
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace x86Emitter
|
} // end namespace x86Emitter
|
||||||
|
|
|
@ -18,156 +18,156 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_MovHL
|
// xImplSimd_MovHL
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Moves to/from high/low portions of an xmm register.
|
// Moves to/from high/low portions of an xmm register.
|
||||||
// These instructions cannot be used in reg/reg form.
|
// These instructions cannot be used in reg/reg form.
|
||||||
//
|
//
|
||||||
struct xImplSimd_MovHL
|
struct xImplSimd_MovHL
|
||||||
{
|
{
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
void PS(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
void PS(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||||
|
|
||||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
void PD(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
void PD(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_MovHL_RtoR
|
// xImplSimd_MovHL_RtoR
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
|
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
|
||||||
// do something kinda different! Fun!
|
// do something kinda different! Fun!
|
||||||
//
|
//
|
||||||
struct xImplSimd_MovHL_RtoR
|
struct xImplSimd_MovHL_RtoR
|
||||||
{
|
{
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_MoveSSE
|
// xImplSimd_MoveSSE
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
|
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
|
||||||
//
|
//
|
||||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||||
// which can be checked for alignment at runtime.
|
// which can be checked for alignment at runtime.
|
||||||
//
|
//
|
||||||
struct xImplSimd_MoveSSE
|
struct xImplSimd_MoveSSE
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
bool isAligned;
|
bool isAligned;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_MoveDQ
|
// xImplSimd_MoveDQ
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Implementations for MOVDQA / MOVDQU
|
// Implementations for MOVDQA / MOVDQU
|
||||||
//
|
//
|
||||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||||
// which can be checked for alignment at runtime.
|
// which can be checked for alignment at runtime.
|
||||||
|
|
||||||
struct xImplSimd_MoveDQ
|
struct xImplSimd_MoveDQ
|
||||||
{
|
{
|
||||||
u8 Prefix;
|
u8 Prefix;
|
||||||
bool isAligned;
|
bool isAligned;
|
||||||
|
|
||||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||||
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_Blend
|
// xImplSimd_Blend
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Blend - Conditional copying of values in src into dest.
|
// Blend - Conditional copying of values in src into dest.
|
||||||
//
|
//
|
||||||
struct xImplSimd_Blend
|
struct xImplSimd_Blend
|
||||||
{
|
{
|
||||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||||
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
|
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
|
||||||
// dword element in a 128-bit operand.
|
// dword element in a 128-bit operand.
|
||||||
//
|
//
|
||||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||||
// to dest, else the dword element in dest is left unchanged.
|
// to dest, else the dword element in dest is left unchanged.
|
||||||
//
|
//
|
||||||
xImplSimd_DestRegImmSSE PS;
|
xImplSimd_DestRegImmSSE PS;
|
||||||
|
|
||||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||||
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
|
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
|
||||||
// quadword element in a 128-bit operand.
|
// quadword element in a 128-bit operand.
|
||||||
//
|
//
|
||||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||||
// to dest, else the dword element in dest is left unchanged.
|
// to dest, else the dword element in dest is left unchanged.
|
||||||
//
|
//
|
||||||
xImplSimd_DestRegImmSSE PD;
|
xImplSimd_DestRegImmSSE PD;
|
||||||
|
|
||||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||||
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||||
// to a dword element in the 128-bit operand.
|
// to a dword element in the 128-bit operand.
|
||||||
//
|
//
|
||||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||||
// to dest, else the dword element in dest is left unchanged.
|
// to dest, else the dword element in dest is left unchanged.
|
||||||
//
|
//
|
||||||
xImplSimd_DestRegSSE VPS;
|
xImplSimd_DestRegSSE VPS;
|
||||||
|
|
||||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||||
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||||
// to a quadword element in the 128-bit operand.
|
// to a quadword element in the 128-bit operand.
|
||||||
//
|
//
|
||||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||||
// to dest, else the dword element in dest is left unchanged.
|
// to dest, else the dword element in dest is left unchanged.
|
||||||
//
|
//
|
||||||
xImplSimd_DestRegSSE VPD;
|
xImplSimd_DestRegSSE VPD;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_PMove
|
// xImplSimd_PMove
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Packed Move with Sign or Zero extension.
|
// Packed Move with Sign or Zero extension.
|
||||||
//
|
//
|
||||||
struct xImplSimd_PMove
|
struct xImplSimd_PMove
|
||||||
{
|
{
|
||||||
u16 OpcodeBase;
|
u16 OpcodeBase;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void BW(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void BW(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void BW(const xRegisterSSE &to, const xIndirect64 &from) const;
|
void BW(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void BD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void BD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void BD(const xRegisterSSE &to, const xIndirect32 &from) const;
|
void BD(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void BQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void BQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void BQ(const xRegisterSSE &to, const xIndirect16 &from) const;
|
void BQ(const xRegisterSSE& to, const xIndirect16& from) const;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void WD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void WD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void WD(const xRegisterSSE &to, const xIndirect64 &from) const;
|
void WD(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void WQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void WQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void WQ(const xRegisterSSE &to, const xIndirect32 &from) const;
|
void WQ(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||||
|
|
||||||
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
||||||
// and store them in dest.
|
// and store them in dest.
|
||||||
void DQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void DQ(const xRegisterSSE &to, const xIndirect64 &from) const;
|
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -18,50 +18,50 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_Shuffle
|
// xImplSimd_Shuffle
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImplSimd_Shuffle
|
struct xImplSimd_Shuffle
|
||||||
{
|
{
|
||||||
inline void _selector_assertion_check(u8 selector) const;
|
inline void _selector_assertion_check(u8 selector) const;
|
||||||
|
|
||||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const;
|
void PS(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const;
|
void PS(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||||
|
|
||||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const;
|
void PD(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const;
|
void PD(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImplSimd_PShuffle
|
// xImplSimd_PShuffle
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImplSimd_PShuffle
|
struct xImplSimd_PShuffle
|
||||||
{
|
{
|
||||||
// Copies doublewords from src and inserts them into dest at dword locations selected
|
// Copies doublewords from src and inserts them into dest at dword locations selected
|
||||||
// with the order operand (8 bit immediate).
|
// with the order operand (8 bit immediate).
|
||||||
const xImplSimd_DestRegImmSSE D;
|
const xImplSimd_DestRegImmSSE D;
|
||||||
|
|
||||||
// Copies words from the low quadword of src and inserts them into the low quadword
|
// Copies words from the low quadword of src and inserts them into the low quadword
|
||||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||||
// The high quadword of src is copied to the high quadword of dest.
|
// The high quadword of src is copied to the high quadword of dest.
|
||||||
const xImplSimd_DestRegImmSSE LW;
|
const xImplSimd_DestRegImmSSE LW;
|
||||||
|
|
||||||
// Copies words from the high quadword of src and inserts them into the high quadword
|
// Copies words from the high quadword of src and inserts them into the high quadword
|
||||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||||
// The low quadword of src is copied to the low quadword of dest.
|
// The low quadword of src is copied to the low quadword of dest.
|
||||||
const xImplSimd_DestRegImmSSE HW;
|
const xImplSimd_DestRegImmSSE HW;
|
||||||
|
|
||||||
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
||||||
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
||||||
// shuffle control mask is set, then constant zero is written in the result byte.
|
// shuffle control mask is set, then constant zero is written in the result byte.
|
||||||
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
||||||
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
||||||
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegEither B;
|
const xImplSimd_DestRegEither B;
|
||||||
|
|
||||||
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
|
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
|
||||||
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air
|
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Copies words from src and inserts them into dest at word locations selected with
|
// Copies words from src and inserts them into dest at word locations selected with
|
||||||
|
@ -94,148 +94,148 @@ struct xImplSimd_PShuffle
|
||||||
void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||||
void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SimdImpl_PUnpack
|
// SimdImpl_PUnpack
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct SimdImpl_PUnpack
|
struct SimdImpl_PUnpack
|
||||||
{
|
{
|
||||||
// Unpack and interleave low-order bytes from src and dest into dest.
|
// Unpack and interleave low-order bytes from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither LBW;
|
const xImplSimd_DestRegEither LBW;
|
||||||
// Unpack and interleave low-order words from src and dest into dest.
|
// Unpack and interleave low-order words from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither LWD;
|
const xImplSimd_DestRegEither LWD;
|
||||||
// Unpack and interleave low-order doublewords from src and dest into dest.
|
// Unpack and interleave low-order doublewords from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither LDQ;
|
const xImplSimd_DestRegEither LDQ;
|
||||||
// Unpack and interleave low-order quadwords from src and dest into dest.
|
// Unpack and interleave low-order quadwords from src and dest into dest.
|
||||||
const xImplSimd_DestRegSSE LQDQ;
|
const xImplSimd_DestRegSSE LQDQ;
|
||||||
|
|
||||||
// Unpack and interleave high-order bytes from src and dest into dest.
|
// Unpack and interleave high-order bytes from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither HBW;
|
const xImplSimd_DestRegEither HBW;
|
||||||
// Unpack and interleave high-order words from src and dest into dest.
|
// Unpack and interleave high-order words from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither HWD;
|
const xImplSimd_DestRegEither HWD;
|
||||||
// Unpack and interleave high-order doublewords from src and dest into dest.
|
// Unpack and interleave high-order doublewords from src and dest into dest.
|
||||||
const xImplSimd_DestRegEither HDQ;
|
const xImplSimd_DestRegEither HDQ;
|
||||||
// Unpack and interleave high-order quadwords from src and dest into dest.
|
// Unpack and interleave high-order quadwords from src and dest into dest.
|
||||||
const xImplSimd_DestRegSSE HQDQ;
|
const xImplSimd_DestRegSSE HQDQ;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SimdImpl_Pack
|
// SimdImpl_Pack
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Pack with Signed or Unsigned Saturation
|
// Pack with Signed or Unsigned Saturation
|
||||||
//
|
//
|
||||||
struct SimdImpl_Pack
|
struct SimdImpl_Pack
|
||||||
{
|
{
|
||||||
// Converts packed signed word integers from src and dest into packed signed
|
// Converts packed signed word integers from src and dest into packed signed
|
||||||
// byte integers in dest, using signed saturation.
|
// byte integers in dest, using signed saturation.
|
||||||
const xImplSimd_DestRegEither SSWB;
|
const xImplSimd_DestRegEither SSWB;
|
||||||
|
|
||||||
// Converts packed signed dword integers from src and dest into packed signed
|
// Converts packed signed dword integers from src and dest into packed signed
|
||||||
// word integers in dest, using signed saturation.
|
// word integers in dest, using signed saturation.
|
||||||
const xImplSimd_DestRegEither SSDW;
|
const xImplSimd_DestRegEither SSDW;
|
||||||
|
|
||||||
// Converts packed unsigned word integers from src and dest into packed unsigned
|
// Converts packed unsigned word integers from src and dest into packed unsigned
|
||||||
// byte integers in dest, using unsigned saturation.
|
// byte integers in dest, using unsigned saturation.
|
||||||
const xImplSimd_DestRegEither USWB;
|
const xImplSimd_DestRegEither USWB;
|
||||||
|
|
||||||
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
|
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
|
||||||
// unsigned word integers in dest, using signed saturation.
|
// unsigned word integers in dest, using signed saturation.
|
||||||
const xImplSimd_DestRegSSE USDW;
|
const xImplSimd_DestRegSSE USDW;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SimdImpl_Unpack
|
// SimdImpl_Unpack
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
struct xImplSimd_Unpack
|
struct xImplSimd_Unpack
|
||||||
{
|
{
|
||||||
// Unpacks the high doubleword [single-precision] values from src and dest into
|
// Unpacks the high doubleword [single-precision] values from src and dest into
|
||||||
// dest, such that the result of dest looks like this:
|
// dest, such that the result of dest looks like this:
|
||||||
// dest[0] <- dest[2]
|
// dest[0] <- dest[2]
|
||||||
// dest[1] <- src[2]
|
// dest[1] <- src[2]
|
||||||
// dest[2] <- dest[3]
|
// dest[2] <- dest[3]
|
||||||
// dest[3] <- src[3]
|
// dest[3] <- src[3]
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegSSE HPS;
|
const xImplSimd_DestRegSSE HPS;
|
||||||
|
|
||||||
// Unpacks the high quadword [double-precision] values from src and dest into
|
// Unpacks the high quadword [double-precision] values from src and dest into
|
||||||
// dest, such that the result of dest looks like this:
|
// dest, such that the result of dest looks like this:
|
||||||
// dest.lo <- dest.hi
|
// dest.lo <- dest.hi
|
||||||
// dest.hi <- src.hi
|
// dest.hi <- src.hi
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegSSE HPD;
|
const xImplSimd_DestRegSSE HPD;
|
||||||
|
|
||||||
// Unpacks the low doubleword [single-precision] values from src and dest into
|
// Unpacks the low doubleword [single-precision] values from src and dest into
|
||||||
// dest, such that the result of dest looks like this:
|
// dest, such that the result of dest looks like this:
|
||||||
// dest[3] <- src[1]
|
// dest[3] <- src[1]
|
||||||
// dest[2] <- dest[1]
|
// dest[2] <- dest[1]
|
||||||
// dest[1] <- src[0]
|
// dest[1] <- src[0]
|
||||||
// dest[0] <- dest[0]
|
// dest[0] <- dest[0]
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegSSE LPS;
|
const xImplSimd_DestRegSSE LPS;
|
||||||
|
|
||||||
// Unpacks the low quadword [double-precision] values from src and dest into
|
// Unpacks the low quadword [double-precision] values from src and dest into
|
||||||
// dest, effectively moving the low portion of src into the upper portion of dest.
|
// dest, effectively moving the low portion of src into the upper portion of dest.
|
||||||
// The result of dest is loaded as such:
|
// The result of dest is loaded as such:
|
||||||
// dest.hi <- src.lo
|
// dest.hi <- src.lo
|
||||||
// dest.lo <- dest.lo [remains unchanged!]
|
// dest.lo <- dest.lo [remains unchanged!]
|
||||||
//
|
//
|
||||||
const xImplSimd_DestRegSSE LPD;
|
const xImplSimd_DestRegSSE LPD;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct xImplSimd_InsertExtractHelper
|
struct xImplSimd_InsertExtractHelper
|
||||||
{
|
{
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||||
void operator()(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
|
void operator()(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||||
|
|
||||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
|
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SimdImpl_PInsert
|
// SimdImpl_PInsert
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// PINSRW/B/D [all but Word form are SSE4.1 only!]
|
// PINSRW/B/D [all but Word form are SSE4.1 only!]
|
||||||
//
|
//
|
||||||
struct xImplSimd_PInsert
|
struct xImplSimd_PInsert
|
||||||
{
|
{
|
||||||
void W(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
|
void W(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||||
void W(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
|
void W(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
|
||||||
|
|
||||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||||
xImplSimd_InsertExtractHelper B;
|
xImplSimd_InsertExtractHelper B;
|
||||||
|
|
||||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||||
xImplSimd_InsertExtractHelper D;
|
xImplSimd_InsertExtractHelper D;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
|
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
|
||||||
//
|
//
|
||||||
// Note: Word form's indirect memory form is only available in SSE4.1.
|
// Note: Word form's indirect memory form is only available in SSE4.1.
|
||||||
//
|
//
|
||||||
struct SimdImpl_PExtract
|
struct SimdImpl_PExtract
|
||||||
{
|
{
|
||||||
// Copies the word element specified by imm8 from src to dest. The upper bits
|
// Copies the word element specified by imm8 from src to dest. The upper bits
|
||||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||||
// word value from src into an x86 32 bit register.
|
// word value from src into an x86 32 bit register.
|
||||||
//
|
//
|
||||||
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
|
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
|
||||||
//
|
//
|
||||||
void W(const xRegister32 &to, const xRegisterSSE &from, u8 imm8) const;
|
void W(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
|
||||||
void W(const xIndirectVoid &dest, const xRegisterSSE &from, u8 imm8) const;
|
void W(const xIndirectVoid& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||||
|
|
||||||
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
|
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
|
||||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||||
// byte value from src into an x86 32 bit register.
|
// byte value from src into an x86 32 bit register.
|
||||||
const xImplSimd_InsertExtractHelper B;
|
const xImplSimd_InsertExtractHelper B;
|
||||||
|
|
||||||
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
|
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
|
||||||
// used to extract any single packed dword value from src into an x86 32 bit register.
|
// used to extract any single packed dword value from src into an x86 32 bit register.
|
||||||
const xImplSimd_InsertExtractHelper D;
|
const xImplSimd_InsertExtractHelper D;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -26,13 +26,13 @@ template <u8 Prefix, u16 Opcode>
|
||||||
class SimdImpl_DestRegSSE
|
class SimdImpl_DestRegSSE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
__forceinline void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const { xOpWrite0F(Prefix, Opcode, to, from); }
|
__forceinline void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const { xOpWrite0F(Prefix, Opcode, to, from); }
|
||||||
__forceinline void operator()(const xRegisterSSE &to, const ModSibBase &from) const
|
__forceinline void operator()(const xRegisterSSE& to, const ModSibBase& from) const
|
||||||
{
|
{
|
||||||
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
|
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
|
||||||
pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load.");
|
pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load.");
|
||||||
xOpWrite0F(Prefix, Opcode, to, from);
|
xOpWrite0F(Prefix, Opcode, to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimdImpl_DestRegSSE() {} //GCWho?
|
SimdImpl_DestRegSSE() {} //GCWho?
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,55 +20,56 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_Test
|
// xImpl_Test
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
struct xImpl_Test
|
struct xImpl_Test
|
||||||
{
|
{
|
||||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||||
void operator()(const xIndirect64orLess &dest, int imm) const;
|
void operator()(const xIndirect64orLess& dest, int imm) const;
|
||||||
void operator()(const xRegisterInt &to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum G8Type {
|
enum G8Type
|
||||||
G8Type_BT = 4,
|
{
|
||||||
G8Type_BTS,
|
G8Type_BT = 4,
|
||||||
G8Type_BTR,
|
G8Type_BTS,
|
||||||
G8Type_BTC,
|
G8Type_BTR,
|
||||||
};
|
G8Type_BTC,
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BSF / BSR
|
// BSF / BSR
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
||||||
//
|
//
|
||||||
struct xImpl_BitScan
|
struct xImpl_BitScan
|
||||||
{
|
{
|
||||||
// 0xbc [fwd] / 0xbd [rev]
|
// 0xbc [fwd] / 0xbd [rev]
|
||||||
u16 Opcode;
|
u16 Opcode;
|
||||||
|
|
||||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
|
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||||
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
|
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// xImpl_Group8
|
// xImpl_Group8
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
||||||
//
|
//
|
||||||
struct xImpl_Group8
|
struct xImpl_Group8
|
||||||
{
|
{
|
||||||
G8Type InstType;
|
G8Type InstType;
|
||||||
|
|
||||||
void operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const;
|
void operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||||
void operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const;
|
void operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const;
|
||||||
|
|
||||||
void operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const;
|
void operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||||
|
|
||||||
void operator()(const xIndirect64 &bitbase, u8 bitoffset) const;
|
void operator()(const xIndirect64& bitbase, u8 bitoffset) const;
|
||||||
void operator()(const xIndirect32 &bitbase, u8 bitoffset) const;
|
void operator()(const xIndirect32& bitbase, u8 bitoffset) const;
|
||||||
void operator()(const xIndirect16 &bitbase, u8 bitoffset) const;
|
void operator()(const xIndirect16& bitbase, u8 bitoffset) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace x86Emitter
|
} // End namespace x86Emitter
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,165 +23,168 @@ namespace x86Emitter
|
||||||
|
|
||||||
#define OpWriteSSE(pre, op) xOpWrite0F(pre, op, to, from)
|
#define OpWriteSSE(pre, op) xOpWrite0F(pre, op, to, from)
|
||||||
|
|
||||||
extern void SimdPrefix(u8 prefix, u16 opcode);
|
extern void SimdPrefix(u8 prefix, u16 opcode);
|
||||||
extern void EmitSibMagic(uint regfield, const void *address, int extraRIPOffset = 0);
|
extern void EmitSibMagic(uint regfield, const void* address, int extraRIPOffset = 0);
|
||||||
extern void EmitSibMagic(uint regfield, const xIndirectVoid &info, int extraRIPOffset = 0);
|
extern void EmitSibMagic(uint regfield, const xIndirectVoid& info, int extraRIPOffset = 0);
|
||||||
extern void EmitSibMagic(uint reg1, const xRegisterBase ®2, int = 0);
|
extern void EmitSibMagic(uint reg1, const xRegisterBase& reg2, int = 0);
|
||||||
extern void EmitSibMagic(const xRegisterBase ®1, const xRegisterBase ®2, int = 0);
|
extern void EmitSibMagic(const xRegisterBase& reg1, const xRegisterBase& reg2, int = 0);
|
||||||
extern void EmitSibMagic(const xRegisterBase ®1, const void *src, int extraRIPOffset = 0);
|
extern void EmitSibMagic(const xRegisterBase& reg1, const void* src, int extraRIPOffset = 0);
|
||||||
extern void EmitSibMagic(const xRegisterBase ®1, const xIndirectVoid &sib, int extraRIPOffset = 0);
|
extern void EmitSibMagic(const xRegisterBase& reg1, const xIndirectVoid& sib, int extraRIPOffset = 0);
|
||||||
|
|
||||||
extern void EmitRex(uint regfield, const void *address);
|
extern void EmitRex(uint regfield, const void* address);
|
||||||
extern void EmitRex(uint regfield, const xIndirectVoid &info);
|
extern void EmitRex(uint regfield, const xIndirectVoid& info);
|
||||||
extern void EmitRex(uint reg1, const xRegisterBase ®2);
|
extern void EmitRex(uint reg1, const xRegisterBase& reg2);
|
||||||
extern void EmitRex(const xRegisterBase ®1, const xRegisterBase ®2);
|
extern void EmitRex(const xRegisterBase& reg1, const xRegisterBase& reg2);
|
||||||
extern void EmitRex(const xRegisterBase ®1, const void *src);
|
extern void EmitRex(const xRegisterBase& reg1, const void* src);
|
||||||
extern void EmitRex(const xRegisterBase ®1, const xIndirectVoid &sib);
|
extern void EmitRex(const xRegisterBase& reg1, const xIndirectVoid& sib);
|
||||||
|
|
||||||
extern void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from);
|
extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void xWrite(T val)
|
inline void xWrite(T val)
|
||||||
{
|
{
|
||||||
*(T *)x86Ptr = val;
|
*(T*)x86Ptr = val;
|
||||||
x86Ptr += sizeof(T);
|
x86Ptr += sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, int extraRIPOffset = 0)
|
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2, int extraRIPOffset = 0)
|
||||||
{
|
{
|
||||||
if (prefix != 0)
|
if (prefix != 0)
|
||||||
xWrite8(prefix);
|
xWrite8(prefix);
|
||||||
EmitRex(param1, param2);
|
EmitRex(param1, param2);
|
||||||
|
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
|
|
||||||
EmitSibMagic(param1, param2, extraRIPOffset);
|
EmitSibMagic(param1, param2, extraRIPOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2)
|
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2)
|
||||||
{
|
{
|
||||||
if (prefix != 0)
|
if (prefix != 0)
|
||||||
xWrite8(prefix);
|
xWrite8(prefix);
|
||||||
EmitRex(param1, param2);
|
EmitRex(param1, param2);
|
||||||
|
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// emitter helpers for xmm instruction with prefixes, most of which are using
|
// emitter helpers for xmm instruction with prefixes, most of which are using
|
||||||
// the basic opcode format (items inside braces denote optional or conditional
|
// the basic opcode format (items inside braces denote optional or conditional
|
||||||
// emission):
|
// emission):
|
||||||
//
|
//
|
||||||
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
||||||
//
|
//
|
||||||
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
||||||
// 0x3a [and other value will result in assertion failue].
|
// 0x3a [and other value will result in assertion failue].
|
||||||
//
|
//
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 ¶m1, const T2 ¶m2)
|
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2)
|
||||||
{
|
{
|
||||||
if (prefix != 0)
|
if (prefix != 0)
|
||||||
xWrite8(prefix);
|
xWrite8(prefix);
|
||||||
EmitRex(param1, param2);
|
EmitRex(param1, param2);
|
||||||
|
|
||||||
SimdPrefix(0, opcode);
|
SimdPrefix(0, opcode);
|
||||||
|
|
||||||
EmitSibMagic(param1, param2);
|
EmitSibMagic(param1, param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 ¶m1, const T2 ¶m2, u8 imm8)
|
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8)
|
||||||
{
|
{
|
||||||
if (prefix != 0)
|
if (prefix != 0)
|
||||||
xWrite8(prefix);
|
xWrite8(prefix);
|
||||||
EmitRex(param1, param2);
|
EmitRex(param1, param2);
|
||||||
|
|
||||||
SimdPrefix(0, opcode);
|
SimdPrefix(0, opcode);
|
||||||
|
|
||||||
EmitSibMagic(param1, param2, 1);
|
EmitSibMagic(param1, param2, 1);
|
||||||
xWrite8(imm8);
|
xWrite8(imm8);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpWrite0F(u16 opcode, const T1 ¶m1, const T2 ¶m2)
|
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2)
|
||||||
{
|
{
|
||||||
xOpWrite0F(0, opcode, param1, param2);
|
xOpWrite0F(0, opcode, param1, param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
__emitinline void xOpWrite0F(u16 opcode, const T1 ¶m1, const T2 ¶m2, u8 imm8)
|
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2, u8 imm8)
|
||||||
{
|
{
|
||||||
xOpWrite0F(0, opcode, param1, param2, imm8);
|
xOpWrite0F(0, opcode, param1, param2, imm8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VEX 2 Bytes Prefix
|
// VEX 2 Bytes Prefix
|
||||||
template <typename T1, typename T2, typename T3>
|
template <typename T1, typename T2, typename T3>
|
||||||
__emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, const T3 ¶m3)
|
__emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3)
|
||||||
{
|
{
|
||||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||||
|
|
||||||
const xRegisterInt ® = param1.IsReg() ? param1 : param2;
|
const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||||
#else
|
#else
|
||||||
u8 nR = 0x80;
|
u8 nR = 0x80;
|
||||||
#endif
|
#endif
|
||||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||||
|
|
||||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||||
|
|
||||||
u8 p =
|
u8 p =
|
||||||
prefix == 0xF2 ? 3 :
|
prefix == 0xF2 ? 3 :
|
||||||
prefix == 0xF3 ? 2 :
|
prefix == 0xF3 ? 2 :
|
||||||
prefix == 0x66 ? 1 : 0;
|
prefix == 0x66 ? 1 :
|
||||||
|
0;
|
||||||
|
|
||||||
xWrite8(0xC5);
|
xWrite8(0xC5);
|
||||||
xWrite8(nR | nv | L | p);
|
xWrite8(nR | nv | L | p);
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
EmitSibMagic(param1, param3);
|
EmitSibMagic(param1, param3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VEX 3 Bytes Prefix
|
// VEX 3 Bytes Prefix
|
||||||
template <typename T1, typename T2, typename T3>
|
template <typename T1, typename T2, typename T3>
|
||||||
__emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, const T3 ¶m3, int w = -1)
|
__emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3, int w = -1)
|
||||||
{
|
{
|
||||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||||
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
|
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
|
||||||
|
|
||||||
const xRegisterInt ® = param1.IsReg() ? param1 : param2;
|
const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||||
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
|
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
|
||||||
u8 nX = 0x40; // likely unused so hardwired to disabled
|
u8 nX = 0x40; // likely unused so hardwired to disabled
|
||||||
#else
|
#else
|
||||||
u8 nR = 0x80;
|
u8 nR = 0x80;
|
||||||
u8 nB = 0x20;
|
u8 nB = 0x20;
|
||||||
u8 nX = 0x40;
|
u8 nX = 0x40;
|
||||||
#endif
|
#endif
|
||||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||||
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
|
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
|
||||||
0x80 * w; // take directly the W value
|
0x80 * w; // take directly the W value
|
||||||
|
|
||||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||||
|
|
||||||
u8 p =
|
u8 p =
|
||||||
prefix == 0xF2 ? 3 :
|
prefix == 0xF2 ? 3 :
|
||||||
prefix == 0xF3 ? 2 :
|
prefix == 0xF3 ? 2 :
|
||||||
prefix == 0x66 ? 1 : 0;
|
prefix == 0x66 ? 1 :
|
||||||
|
0;
|
||||||
|
|
||||||
u8 m =
|
u8 m =
|
||||||
mb_prefix == 0x3A ? 3 :
|
mb_prefix == 0x3A ? 3 :
|
||||||
mb_prefix == 0x38 ? 2 : 1;
|
mb_prefix == 0x38 ? 2 :
|
||||||
|
1;
|
||||||
|
|
||||||
xWrite8(0xC4);
|
xWrite8(0xC4);
|
||||||
xWrite8(nR | nX | nB | m);
|
xWrite8(nR | nX | nB | m);
|
||||||
xWrite8(W | nv | L | p);
|
xWrite8(W | nv | L | p);
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
EmitSibMagic(param1, param3);
|
EmitSibMagic(param1, param3);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -33,215 +33,253 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
void xImpl_JmpCall::operator()(const xAddressReg &absreg) const {
|
void xImpl_JmpCall::operator()(const xAddressReg& absreg) const
|
||||||
// Jumps are always wide and don't need the rex.W
|
{
|
||||||
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
// Jumps are always wide and don't need the rex.W
|
||||||
}
|
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
||||||
void xImpl_JmpCall::operator()(const xIndirectNative &src) const {
|
}
|
||||||
// Jumps are always wide and don't need the rex.W
|
void xImpl_JmpCall::operator()(const xIndirectNative& src) const
|
||||||
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
{
|
||||||
xWrite8(0xff);
|
// Jumps are always wide and don't need the rex.W
|
||||||
EmitSibMagic(isJmp ? 4 : 2, src);
|
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
||||||
}
|
xWrite8(0xff);
|
||||||
|
EmitSibMagic(isJmp ? 4 : 2, src);
|
||||||
|
}
|
||||||
|
|
||||||
const xImpl_JmpCall xJMP = {true};
|
const xImpl_JmpCall xJMP = {true};
|
||||||
const xImpl_JmpCall xCALL = {false};
|
const xImpl_JmpCall xCALL = {false};
|
||||||
|
|
||||||
|
|
||||||
template <typename Reg1, typename Reg2>
|
template <typename Reg1, typename Reg2>
|
||||||
void prepareRegsForFastcall(const Reg1 &a1, const Reg2 &a2) {
|
void prepareRegsForFastcall(const Reg1& a1, const Reg2& a2)
|
||||||
if (a1.IsEmpty()) return;
|
{
|
||||||
|
if (a1.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
||||||
if (a2.Id != arg1reg.Id) {
|
if (a2.Id != arg1reg.Id)
|
||||||
xMOV(Reg1(arg1reg), a1);
|
{
|
||||||
if (!a2.IsEmpty()) {
|
xMOV(Reg1(arg1reg), a1);
|
||||||
xMOV(Reg2(arg2reg), a2);
|
if (!a2.IsEmpty())
|
||||||
}
|
{
|
||||||
} else if (a1.Id != arg2reg.Id) {
|
xMOV(Reg2(arg2reg), a2);
|
||||||
xMOV(Reg2(arg2reg), a2);
|
}
|
||||||
xMOV(Reg1(arg1reg), a1);
|
}
|
||||||
} else {
|
else if (a1.Id != arg2reg.Id)
|
||||||
xPUSH(a1);
|
{
|
||||||
xMOV(Reg2(arg2reg), a2);
|
xMOV(Reg2(arg2reg), a2);
|
||||||
xPOP(Reg1(arg1reg));
|
xMOV(Reg1(arg1reg), a1);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
xPUSH(a1);
|
||||||
|
xMOV(Reg2(arg2reg), a2);
|
||||||
|
xPOP(Reg1(arg1reg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, const xRegister32 &a1, const xRegister32 &a2) const {
|
void xImpl_FastCall::operator()(void* f, const xRegister32& a1, const xRegister32& a2) const
|
||||||
prepareRegsForFastcall(a1, a2);
|
{
|
||||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
prepareRegsForFastcall(a1, a2);
|
||||||
if ((sptr)disp == (s32)disp) {
|
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||||
xCALL(f);
|
if ((sptr)disp == (s32)disp)
|
||||||
} else {
|
{
|
||||||
xMOV(rax, ptrNative[f]);
|
xCALL(f);
|
||||||
xCALL(rax);
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
xMOV(rax, ptrNative[f]);
|
||||||
|
xCALL(rax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
void xImpl_FastCall::operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||||
prepareRegsForFastcall(a1, a2);
|
{
|
||||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
prepareRegsForFastcall(a1, a2);
|
||||||
if ((sptr)disp == (s32)disp) {
|
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||||
xCALL(f);
|
if ((sptr)disp == (s32)disp)
|
||||||
} else {
|
{
|
||||||
xMOV(rax, ptrNative[f]);
|
xCALL(f);
|
||||||
xCALL(rax);
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
xMOV(rax, ptrNative[f]);
|
||||||
|
xCALL(rax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegisterLong& a2) const
|
||||||
if (!a2.IsEmpty()) { xMOV(arg2reg, a2); }
|
{
|
||||||
xMOV(arg1reg, a1);
|
if (!a2.IsEmpty())
|
||||||
(*this)(f, arg1reg, arg2reg);
|
{
|
||||||
}
|
xMOV(arg2reg, a2);
|
||||||
|
}
|
||||||
|
xMOV(arg1reg, a1);
|
||||||
|
(*this)(f, arg1reg, arg2reg);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, void *a1) const {
|
void xImpl_FastCall::operator()(void* f, void* a1) const
|
||||||
xLEA(arg1reg, ptr[a1]);
|
{
|
||||||
(*this)(f, arg1reg, arg2reg);
|
xLEA(arg1reg, ptr[a1]);
|
||||||
}
|
(*this)(f, arg1reg, arg2reg);
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegister32 &a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegister32& a2) const
|
||||||
if (!a2.IsEmpty()) { xMOV(arg2regd, a2); }
|
{
|
||||||
xMOV(arg1regd, a1);
|
if (!a2.IsEmpty())
|
||||||
(*this)(f, arg1regd, arg2regd);
|
{
|
||||||
}
|
xMOV(arg2regd, a2);
|
||||||
|
}
|
||||||
|
xMOV(arg1regd, a1);
|
||||||
|
(*this)(f, arg1regd, arg2regd);
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, const xIndirect32 &a1) const {
|
void xImpl_FastCall::operator()(void* f, const xIndirect32& a1) const
|
||||||
xMOV(arg1regd, a1);
|
{
|
||||||
(*this)(f, arg1regd);
|
xMOV(arg1regd, a1);
|
||||||
}
|
(*this)(f, arg1regd);
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, u32 a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, u32 a2) const
|
||||||
xMOV(arg1regd, a1);
|
{
|
||||||
xMOV(arg2regd, a2);
|
xMOV(arg1regd, a1);
|
||||||
(*this)(f, arg1regd, arg2regd);
|
xMOV(arg2regd, a2);
|
||||||
}
|
(*this)(f, arg1regd, arg2regd);
|
||||||
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(const xIndirectNative &f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(const xIndirectNative& f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||||
prepareRegsForFastcall(a1, a2);
|
{
|
||||||
xCALL(f);
|
prepareRegsForFastcall(a1, a2);
|
||||||
}
|
xCALL(f);
|
||||||
|
}
|
||||||
|
|
||||||
const xImpl_FastCall xFastCall = {};
|
const xImpl_FastCall xFastCall = {};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
|
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
|
||||||
// (displacements should be assigned relative to the end of the jump instruction,
|
// (displacements should be assigned relative to the end of the jump instruction,
|
||||||
// or in other words *(retval+1) )
|
// or in other words *(retval+1) )
|
||||||
__emitinline s32 *xJcc32(JccComparisonType comparison, s32 displacement)
|
__emitinline s32* xJcc32(JccComparisonType comparison, s32 displacement)
|
||||||
{
|
{
|
||||||
if (comparison == Jcc_Unconditional)
|
if (comparison == Jcc_Unconditional)
|
||||||
xWrite8(0xe9);
|
xWrite8(0xe9);
|
||||||
else {
|
else
|
||||||
xWrite8(0x0f);
|
{
|
||||||
xWrite8(0x80 | comparison);
|
xWrite8(0x0f);
|
||||||
}
|
xWrite8(0x80 | comparison);
|
||||||
xWrite<s32>(displacement);
|
}
|
||||||
|
xWrite<s32>(displacement);
|
||||||
|
|
||||||
return ((s32 *)xGetPtr()) - 1;
|
return ((s32*)xGetPtr()) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
|
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
|
||||||
// (displacements should be assigned relative to the end of the jump instruction,
|
// (displacements should be assigned relative to the end of the jump instruction,
|
||||||
// or in other words *(retval+1) )
|
// or in other words *(retval+1) )
|
||||||
__emitinline s8 *xJcc8(JccComparisonType comparison, s8 displacement)
|
__emitinline s8* xJcc8(JccComparisonType comparison, s8 displacement)
|
||||||
{
|
{
|
||||||
xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison));
|
xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison));
|
||||||
xWrite<s8>(displacement);
|
xWrite<s8>(displacement);
|
||||||
return (s8 *)xGetPtr() - 1;
|
return (s8*)xGetPtr() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
||||||
// (usually a backwards jump)
|
// (usually a backwards jump)
|
||||||
//
|
//
|
||||||
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
||||||
// to slide forward in the event of an 8 bit displacement.
|
// to slide forward in the event of an 8 bit displacement.
|
||||||
//
|
//
|
||||||
__emitinline void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward)
|
__emitinline void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward)
|
||||||
{
|
{
|
||||||
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
||||||
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
||||||
|
|
||||||
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
||||||
displacement8 -= slideVal;
|
displacement8 -= slideVal;
|
||||||
|
|
||||||
if (slideForward) {
|
if (slideForward)
|
||||||
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
{
|
||||||
}
|
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
||||||
|
}
|
||||||
|
|
||||||
if (is_s8(displacement8))
|
if (is_s8(displacement8))
|
||||||
xJcc8(comparison, displacement8);
|
xJcc8(comparison, displacement8);
|
||||||
else {
|
else
|
||||||
// Perform a 32 bit jump instead. :(
|
{
|
||||||
s32 *bah = xJcc32(comparison);
|
// Perform a 32 bit jump instead. :(
|
||||||
sptr distance = (sptr)target - (sptr)xGetPtr();
|
s32* bah = xJcc32(comparison);
|
||||||
|
sptr distance = (sptr)target - (sptr)xGetPtr();
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
// This assert won't physically happen on x86 targets
|
// This assert won't physically happen on x86 targets
|
||||||
pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register");
|
pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
*bah = (s32)distance;
|
*bah = (s32)distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
|
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
|
||||||
// a jump (either 8 or 32 bit) is generated.
|
// a jump (either 8 or 32 bit) is generated.
|
||||||
__emitinline void xJcc(JccComparisonType comparison, const void *target)
|
__emitinline void xJcc(JccComparisonType comparison, const void* target)
|
||||||
{
|
{
|
||||||
xJccKnownTarget(comparison, target, false);
|
xJccKnownTarget(comparison, target, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
|
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
|
||||||
{
|
{
|
||||||
pxAssert(opsize == 1 || opsize == 4);
|
pxAssert(opsize == 1 || opsize == 4);
|
||||||
pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type.");
|
pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type.");
|
||||||
|
|
||||||
BasePtr = (s8 *)xGetPtr() +
|
BasePtr = (s8*)xGetPtr() +
|
||||||
((opsize == 1) ? 2 : // j8's are always 2 bytes.
|
((opsize == 1) ? 2 : // j8's are always 2 bytes.
|
||||||
((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes
|
((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes
|
||||||
|
|
||||||
if (opsize == 1)
|
if (opsize == 1)
|
||||||
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
||||||
else {
|
else
|
||||||
if (cctype == Jcc_Unconditional)
|
{
|
||||||
xWrite8(0xe9);
|
if (cctype == Jcc_Unconditional)
|
||||||
else {
|
xWrite8(0xe9);
|
||||||
xWrite8(0x0f);
|
else
|
||||||
xWrite8(0x80 | cctype);
|
{
|
||||||
}
|
xWrite8(0x0f);
|
||||||
}
|
xWrite8(0x80 | cctype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
xAdvancePtr(opsize);
|
xAdvancePtr(opsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xForwardJumpBase::_setTarget(uint opsize) const
|
void xForwardJumpBase::_setTarget(uint opsize) const
|
||||||
{
|
{
|
||||||
pxAssertDev(BasePtr != NULL, "");
|
pxAssertDev(BasePtr != NULL, "");
|
||||||
|
|
||||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||||
if (opsize == 1) {
|
if (opsize == 1)
|
||||||
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
{
|
||||||
BasePtr[-1] = (s8)displacement;
|
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
||||||
} else {
|
BasePtr[-1] = (s8)displacement;
|
||||||
// full displacement, no sanity checks needed :D
|
}
|
||||||
((s32 *)BasePtr)[-1] = displacement;
|
else
|
||||||
}
|
{
|
||||||
}
|
// full displacement, no sanity checks needed :D
|
||||||
|
((s32*)BasePtr)[-1] = displacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
||||||
__fi JccComparisonType xInvertCond(JccComparisonType src)
|
__fi JccComparisonType xInvertCond(JccComparisonType src)
|
||||||
{
|
{
|
||||||
pxAssert(src != Jcc_Unknown);
|
pxAssert(src != Jcc_Unknown);
|
||||||
if (Jcc_Unconditional == src)
|
if (Jcc_Unconditional == src)
|
||||||
return Jcc_Unconditional;
|
return Jcc_Unconditional;
|
||||||
|
|
||||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||||
return (JccComparisonType)((int)src ^ 1);
|
return (JccComparisonType)((int)src ^ 1);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -29,24 +29,24 @@
|
||||||
|
|
||||||
emitterT void ModRM(uint mod, uint reg, uint rm)
|
emitterT void ModRM(uint mod, uint reg, uint rm)
|
||||||
{
|
{
|
||||||
// Note: Following assertions are for legacy support only.
|
// Note: Following assertions are for legacy support only.
|
||||||
// The new emitter performs these sanity checks during operand construction, so these
|
// The new emitter performs these sanity checks during operand construction, so these
|
||||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||||
pxAssert(mod < 4);
|
pxAssert(mod < 4);
|
||||||
pxAssert(reg < 8);
|
pxAssert(reg < 8);
|
||||||
pxAssert(rm < 8);
|
pxAssert(rm < 8);
|
||||||
xWrite8((mod << 6) | (reg << 3) | rm);
|
xWrite8((mod << 6) | (reg << 3) | rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void SibSB(uint ss, uint index, uint base)
|
emitterT void SibSB(uint ss, uint index, uint base)
|
||||||
{
|
{
|
||||||
// Note: Following asserts are for legacy support only.
|
// Note: Following asserts are for legacy support only.
|
||||||
// The new emitter performs these sanity checks during operand construction, so these
|
// The new emitter performs these sanity checks during operand construction, so these
|
||||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||||
pxAssert(ss < 4);
|
pxAssert(ss < 4);
|
||||||
pxAssert(index < 8);
|
pxAssert(index < 8);
|
||||||
pxAssert(base < 8);
|
pxAssert(base < 8);
|
||||||
xWrite8((ss << 6) | (index << 3) | base);
|
xWrite8((ss << 6) | (index << 3) | base);
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace x86Emitter;
|
using namespace x86Emitter;
|
||||||
|
@ -57,33 +57,33 @@ using namespace x86Emitter;
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
emitterT u8 *J8Rel(int cc, int to)
|
emitterT u8* J8Rel(int cc, int to)
|
||||||
{
|
{
|
||||||
xWrite8(cc);
|
xWrite8(cc);
|
||||||
xWrite8(to);
|
xWrite8(to);
|
||||||
return (u8 *)(x86Ptr - 1);
|
return (u8*)(x86Ptr - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT u16 *J16Rel(int cc, u32 to)
|
emitterT u16* J16Rel(int cc, u32 to)
|
||||||
{
|
{
|
||||||
xWrite16(0x0F66);
|
xWrite16(0x0F66);
|
||||||
xWrite8(cc);
|
xWrite8(cc);
|
||||||
xWrite16(to);
|
xWrite16(to);
|
||||||
return (u16 *)(x86Ptr - 2);
|
return (u16*)(x86Ptr - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT u32 *J32Rel(int cc, u32 to)
|
emitterT u32* J32Rel(int cc, u32 to)
|
||||||
{
|
{
|
||||||
xWrite8(0x0F);
|
xWrite8(0x0F);
|
||||||
xWrite8(cc);
|
xWrite8(cc);
|
||||||
xWrite32(to);
|
xWrite32(to);
|
||||||
return (u32 *)(x86Ptr - 4);
|
return (u32*)(x86Ptr - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
emitterT void x86SetPtr(u8 *ptr)
|
emitterT void x86SetPtr(u8* ptr)
|
||||||
{
|
{
|
||||||
x86Ptr = ptr;
|
x86Ptr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -92,57 +92,61 @@ emitterT void x86SetPtr(u8 *ptr)
|
||||||
// I don't auto-inline these because of the console logging in case of error, which tends
|
// I don't auto-inline these because of the console logging in case of error, which tends
|
||||||
// to cause quite a bit of code bloat.
|
// to cause quite a bit of code bloat.
|
||||||
//
|
//
|
||||||
void x86SetJ8(u8 *j8)
|
void x86SetJ8(u8* j8)
|
||||||
{
|
{
|
||||||
u32 jump = (x86Ptr - j8) - 1;
|
u32 jump = (x86Ptr - j8) - 1;
|
||||||
|
|
||||||
if (jump > 0x7f) {
|
if (jump > 0x7f)
|
||||||
Console.Error("j8 greater than 0x7f!!");
|
{
|
||||||
assert(0);
|
Console.Error("j8 greater than 0x7f!!");
|
||||||
}
|
assert(0);
|
||||||
*j8 = (u8)jump;
|
}
|
||||||
|
*j8 = (u8)jump;
|
||||||
}
|
}
|
||||||
|
|
||||||
void x86SetJ8A(u8 *j8)
|
void x86SetJ8A(u8* j8)
|
||||||
{
|
{
|
||||||
u32 jump = (x86Ptr - j8) - 1;
|
u32 jump = (x86Ptr - j8) - 1;
|
||||||
|
|
||||||
if (jump > 0x7f) {
|
if (jump > 0x7f)
|
||||||
Console.Error("j8 greater than 0x7f!!");
|
{
|
||||||
assert(0);
|
Console.Error("j8 greater than 0x7f!!");
|
||||||
}
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (((uptr)x86Ptr & 0xf) > 4) {
|
if (((uptr)x86Ptr & 0xf) > 4)
|
||||||
|
{
|
||||||
|
|
||||||
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
||||||
|
|
||||||
if (newjump <= 0x7f) {
|
if (newjump <= 0x7f)
|
||||||
jump = newjump;
|
{
|
||||||
while ((uptr)x86Ptr & 0xf)
|
jump = newjump;
|
||||||
*x86Ptr++ = 0x90;
|
while ((uptr)x86Ptr & 0xf)
|
||||||
}
|
*x86Ptr++ = 0x90;
|
||||||
}
|
}
|
||||||
*j8 = (u8)jump;
|
}
|
||||||
|
*j8 = (u8)jump;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
emitterT void x86SetJ32(u32 *j32)
|
emitterT void x86SetJ32(u32* j32)
|
||||||
{
|
{
|
||||||
*j32 = (x86Ptr - (u8 *)j32) - 4;
|
*j32 = (x86Ptr - (u8*)j32) - 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void x86SetJ32A(u32 *j32)
|
emitterT void x86SetJ32A(u32* j32)
|
||||||
{
|
{
|
||||||
while ((uptr)x86Ptr & 0xf)
|
while ((uptr)x86Ptr & 0xf)
|
||||||
*x86Ptr++ = 0x90;
|
*x86Ptr++ = 0x90;
|
||||||
x86SetJ32(j32);
|
x86SetJ32(j32);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
emitterT void x86Align(int bytes)
|
emitterT void x86Align(int bytes)
|
||||||
{
|
{
|
||||||
// forward align
|
// forward align
|
||||||
x86Ptr = (u8 *)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
|
x86Ptr = (u8*)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
|
@ -154,262 +158,262 @@ emitterT void x86Align(int bytes)
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|
||||||
/* jmp rel8 */
|
/* jmp rel8 */
|
||||||
emitterT u8 *JMP8(u8 to)
|
emitterT u8* JMP8(u8 to)
|
||||||
{
|
{
|
||||||
xWrite8(0xEB);
|
xWrite8(0xEB);
|
||||||
xWrite8(to);
|
xWrite8(to);
|
||||||
return x86Ptr - 1;
|
return x86Ptr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jmp rel32 */
|
/* jmp rel32 */
|
||||||
emitterT u32 *JMP32(uptr to)
|
emitterT u32* JMP32(uptr to)
|
||||||
{
|
{
|
||||||
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
|
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
|
||||||
xWrite8(0xE9);
|
xWrite8(0xE9);
|
||||||
xWrite32(to);
|
xWrite32(to);
|
||||||
return (u32 *)(x86Ptr - 4);
|
return (u32*)(x86Ptr - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jp rel8 */
|
/* jp rel8 */
|
||||||
emitterT u8 *JP8(u8 to)
|
emitterT u8* JP8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7A, to);
|
return J8Rel(0x7A, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnp rel8 */
|
/* jnp rel8 */
|
||||||
emitterT u8 *JNP8(u8 to)
|
emitterT u8* JNP8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7B, to);
|
return J8Rel(0x7B, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* je rel8 */
|
/* je rel8 */
|
||||||
emitterT u8 *JE8(u8 to)
|
emitterT u8* JE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x74, to);
|
return J8Rel(0x74, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jz rel8 */
|
/* jz rel8 */
|
||||||
emitterT u8 *JZ8(u8 to)
|
emitterT u8* JZ8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x74, to);
|
return J8Rel(0x74, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* js rel8 */
|
/* js rel8 */
|
||||||
emitterT u8 *JS8(u8 to)
|
emitterT u8* JS8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x78, to);
|
return J8Rel(0x78, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jns rel8 */
|
/* jns rel8 */
|
||||||
emitterT u8 *JNS8(u8 to)
|
emitterT u8* JNS8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x79, to);
|
return J8Rel(0x79, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jg rel8 */
|
/* jg rel8 */
|
||||||
emitterT u8 *JG8(u8 to)
|
emitterT u8* JG8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7F, to);
|
return J8Rel(0x7F, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jge rel8 */
|
/* jge rel8 */
|
||||||
emitterT u8 *JGE8(u8 to)
|
emitterT u8* JGE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7D, to);
|
return J8Rel(0x7D, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jl rel8 */
|
/* jl rel8 */
|
||||||
emitterT u8 *JL8(u8 to)
|
emitterT u8* JL8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7C, to);
|
return J8Rel(0x7C, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ja rel8 */
|
/* ja rel8 */
|
||||||
emitterT u8 *JA8(u8 to)
|
emitterT u8* JA8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x77, to);
|
return J8Rel(0x77, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT u8 *JAE8(u8 to)
|
emitterT u8* JAE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x73, to);
|
return J8Rel(0x73, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jb rel8 */
|
/* jb rel8 */
|
||||||
emitterT u8 *JB8(u8 to)
|
emitterT u8* JB8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x72, to);
|
return J8Rel(0x72, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jbe rel8 */
|
/* jbe rel8 */
|
||||||
emitterT u8 *JBE8(u8 to)
|
emitterT u8* JBE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x76, to);
|
return J8Rel(0x76, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jle rel8 */
|
/* jle rel8 */
|
||||||
emitterT u8 *JLE8(u8 to)
|
emitterT u8* JLE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7E, to);
|
return J8Rel(0x7E, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jne rel8 */
|
/* jne rel8 */
|
||||||
emitterT u8 *JNE8(u8 to)
|
emitterT u8* JNE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x75, to);
|
return J8Rel(0x75, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnz rel8 */
|
/* jnz rel8 */
|
||||||
emitterT u8 *JNZ8(u8 to)
|
emitterT u8* JNZ8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x75, to);
|
return J8Rel(0x75, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jng rel8 */
|
/* jng rel8 */
|
||||||
emitterT u8 *JNG8(u8 to)
|
emitterT u8* JNG8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7E, to);
|
return J8Rel(0x7E, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnge rel8 */
|
/* jnge rel8 */
|
||||||
emitterT u8 *JNGE8(u8 to)
|
emitterT u8* JNGE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7C, to);
|
return J8Rel(0x7C, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnl rel8 */
|
/* jnl rel8 */
|
||||||
emitterT u8 *JNL8(u8 to)
|
emitterT u8* JNL8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7D, to);
|
return J8Rel(0x7D, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnle rel8 */
|
/* jnle rel8 */
|
||||||
emitterT u8 *JNLE8(u8 to)
|
emitterT u8* JNLE8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x7F, to);
|
return J8Rel(0x7F, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jo rel8 */
|
/* jo rel8 */
|
||||||
emitterT u8 *JO8(u8 to)
|
emitterT u8* JO8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x70, to);
|
return J8Rel(0x70, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jno rel8 */
|
/* jno rel8 */
|
||||||
emitterT u8 *JNO8(u8 to)
|
emitterT u8* JNO8(u8 to)
|
||||||
{
|
{
|
||||||
return J8Rel(0x71, to);
|
return J8Rel(0x71, to);
|
||||||
}
|
}
|
||||||
// jb rel32
|
// jb rel32
|
||||||
emitterT u32 *JB32(u32 to)
|
emitterT u32* JB32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x82, to);
|
return J32Rel(0x82, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* je rel32 */
|
/* je rel32 */
|
||||||
emitterT u32 *JE32(u32 to)
|
emitterT u32* JE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x84, to);
|
return J32Rel(0x84, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jz rel32 */
|
/* jz rel32 */
|
||||||
emitterT u32 *JZ32(u32 to)
|
emitterT u32* JZ32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x84, to);
|
return J32Rel(0x84, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* js rel32 */
|
/* js rel32 */
|
||||||
emitterT u32 *JS32(u32 to)
|
emitterT u32* JS32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x88, to);
|
return J32Rel(0x88, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jns rel32 */
|
/* jns rel32 */
|
||||||
emitterT u32 *JNS32(u32 to)
|
emitterT u32* JNS32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x89, to);
|
return J32Rel(0x89, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jg rel32 */
|
/* jg rel32 */
|
||||||
emitterT u32 *JG32(u32 to)
|
emitterT u32* JG32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8F, to);
|
return J32Rel(0x8F, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jge rel32 */
|
/* jge rel32 */
|
||||||
emitterT u32 *JGE32(u32 to)
|
emitterT u32* JGE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8D, to);
|
return J32Rel(0x8D, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jl rel32 */
|
/* jl rel32 */
|
||||||
emitterT u32 *JL32(u32 to)
|
emitterT u32* JL32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8C, to);
|
return J32Rel(0x8C, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jle rel32 */
|
/* jle rel32 */
|
||||||
emitterT u32 *JLE32(u32 to)
|
emitterT u32* JLE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8E, to);
|
return J32Rel(0x8E, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ja rel32 */
|
/* ja rel32 */
|
||||||
emitterT u32 *JA32(u32 to)
|
emitterT u32* JA32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x87, to);
|
return J32Rel(0x87, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jae rel32 */
|
/* jae rel32 */
|
||||||
emitterT u32 *JAE32(u32 to)
|
emitterT u32* JAE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x83, to);
|
return J32Rel(0x83, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jne rel32 */
|
/* jne rel32 */
|
||||||
emitterT u32 *JNE32(u32 to)
|
emitterT u32* JNE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x85, to);
|
return J32Rel(0x85, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnz rel32 */
|
/* jnz rel32 */
|
||||||
emitterT u32 *JNZ32(u32 to)
|
emitterT u32* JNZ32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x85, to);
|
return J32Rel(0x85, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jng rel32 */
|
/* jng rel32 */
|
||||||
emitterT u32 *JNG32(u32 to)
|
emitterT u32* JNG32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8E, to);
|
return J32Rel(0x8E, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnge rel32 */
|
/* jnge rel32 */
|
||||||
emitterT u32 *JNGE32(u32 to)
|
emitterT u32* JNGE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8C, to);
|
return J32Rel(0x8C, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnl rel32 */
|
/* jnl rel32 */
|
||||||
emitterT u32 *JNL32(u32 to)
|
emitterT u32* JNL32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8D, to);
|
return J32Rel(0x8D, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jnle rel32 */
|
/* jnle rel32 */
|
||||||
emitterT u32 *JNLE32(u32 to)
|
emitterT u32* JNLE32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x8F, to);
|
return J32Rel(0x8F, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jo rel32 */
|
/* jo rel32 */
|
||||||
emitterT u32 *JO32(u32 to)
|
emitterT u32* JO32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x80, to);
|
return J32Rel(0x80, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jno rel32 */
|
/* jno rel32 */
|
||||||
emitterT u32 *JNO32(u32 to)
|
emitterT u32* JNO32(u32 to)
|
||||||
{
|
{
|
||||||
return J32Rel(0x81, to);
|
return J32Rel(0x81, to);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,13 @@
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// legacy jump/align functions
|
// legacy jump/align functions
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
ATTR_DEP extern void x86SetPtr(u8 *ptr);
|
ATTR_DEP extern void x86SetPtr(u8* ptr);
|
||||||
ATTR_DEP extern void x86SetJ8(u8 *j8);
|
ATTR_DEP extern void x86SetJ8(u8* j8);
|
||||||
ATTR_DEP extern void x86SetJ8A(u8 *j8);
|
ATTR_DEP extern void x86SetJ8A(u8* j8);
|
||||||
ATTR_DEP extern void x86SetJ16(u16 *j16);
|
ATTR_DEP extern void x86SetJ16(u16* j16);
|
||||||
ATTR_DEP extern void x86SetJ16A(u16 *j16);
|
ATTR_DEP extern void x86SetJ16A(u16* j16);
|
||||||
ATTR_DEP extern void x86SetJ32(u32 *j32);
|
ATTR_DEP extern void x86SetJ32(u32* j32);
|
||||||
ATTR_DEP extern void x86SetJ32A(u32 *j32);
|
ATTR_DEP extern void x86SetJ32A(u32* j32);
|
||||||
ATTR_DEP extern void x86Align(int bytes);
|
ATTR_DEP extern void x86Align(int bytes);
|
||||||
ATTR_DEP extern void x86AlignExecutable(int align);
|
ATTR_DEP extern void x86AlignExecutable(int align);
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
@ -41,55 +41,55 @@ ATTR_DEP extern void x86AlignExecutable(int align);
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|
||||||
// jmp rel8
|
// jmp rel8
|
||||||
ATTR_DEP extern u8 *JMP8(u8 to);
|
ATTR_DEP extern u8* JMP8(u8 to);
|
||||||
|
|
||||||
// jmp rel32
|
// jmp rel32
|
||||||
ATTR_DEP extern u32 *JMP32(uptr to);
|
ATTR_DEP extern u32* JMP32(uptr to);
|
||||||
|
|
||||||
// jp rel8
|
// jp rel8
|
||||||
ATTR_DEP extern u8 *JP8(u8 to);
|
ATTR_DEP extern u8* JP8(u8 to);
|
||||||
// jnp rel8
|
// jnp rel8
|
||||||
ATTR_DEP extern u8 *JNP8(u8 to);
|
ATTR_DEP extern u8* JNP8(u8 to);
|
||||||
// je rel8
|
// je rel8
|
||||||
ATTR_DEP extern u8 *JE8(u8 to);
|
ATTR_DEP extern u8* JE8(u8 to);
|
||||||
// jz rel8
|
// jz rel8
|
||||||
ATTR_DEP extern u8 *JZ8(u8 to);
|
ATTR_DEP extern u8* JZ8(u8 to);
|
||||||
// jg rel8
|
// jg rel8
|
||||||
ATTR_DEP extern u8 *JG8(u8 to);
|
ATTR_DEP extern u8* JG8(u8 to);
|
||||||
// jge rel8
|
// jge rel8
|
||||||
ATTR_DEP extern u8 *JGE8(u8 to);
|
ATTR_DEP extern u8* JGE8(u8 to);
|
||||||
// js rel8
|
// js rel8
|
||||||
ATTR_DEP extern u8 *JS8(u8 to);
|
ATTR_DEP extern u8* JS8(u8 to);
|
||||||
// jns rel8
|
// jns rel8
|
||||||
ATTR_DEP extern u8 *JNS8(u8 to);
|
ATTR_DEP extern u8* JNS8(u8 to);
|
||||||
// jl rel8
|
// jl rel8
|
||||||
ATTR_DEP extern u8 *JL8(u8 to);
|
ATTR_DEP extern u8* JL8(u8 to);
|
||||||
// ja rel8
|
// ja rel8
|
||||||
ATTR_DEP extern u8 *JA8(u8 to);
|
ATTR_DEP extern u8* JA8(u8 to);
|
||||||
// jae rel8
|
// jae rel8
|
||||||
ATTR_DEP extern u8 *JAE8(u8 to);
|
ATTR_DEP extern u8* JAE8(u8 to);
|
||||||
// jb rel8
|
// jb rel8
|
||||||
ATTR_DEP extern u8 *JB8(u8 to);
|
ATTR_DEP extern u8* JB8(u8 to);
|
||||||
// jbe rel8
|
// jbe rel8
|
||||||
ATTR_DEP extern u8 *JBE8(u8 to);
|
ATTR_DEP extern u8* JBE8(u8 to);
|
||||||
// jle rel8
|
// jle rel8
|
||||||
ATTR_DEP extern u8 *JLE8(u8 to);
|
ATTR_DEP extern u8* JLE8(u8 to);
|
||||||
// jne rel8
|
// jne rel8
|
||||||
ATTR_DEP extern u8 *JNE8(u8 to);
|
ATTR_DEP extern u8* JNE8(u8 to);
|
||||||
// jnz rel8
|
// jnz rel8
|
||||||
ATTR_DEP extern u8 *JNZ8(u8 to);
|
ATTR_DEP extern u8* JNZ8(u8 to);
|
||||||
// jng rel8
|
// jng rel8
|
||||||
ATTR_DEP extern u8 *JNG8(u8 to);
|
ATTR_DEP extern u8* JNG8(u8 to);
|
||||||
// jnge rel8
|
// jnge rel8
|
||||||
ATTR_DEP extern u8 *JNGE8(u8 to);
|
ATTR_DEP extern u8* JNGE8(u8 to);
|
||||||
// jnl rel8
|
// jnl rel8
|
||||||
ATTR_DEP extern u8 *JNL8(u8 to);
|
ATTR_DEP extern u8* JNL8(u8 to);
|
||||||
// jnle rel8
|
// jnle rel8
|
||||||
ATTR_DEP extern u8 *JNLE8(u8 to);
|
ATTR_DEP extern u8* JNLE8(u8 to);
|
||||||
// jo rel8
|
// jo rel8
|
||||||
ATTR_DEP extern u8 *JO8(u8 to);
|
ATTR_DEP extern u8* JO8(u8 to);
|
||||||
// jno rel8
|
// jno rel8
|
||||||
ATTR_DEP extern u8 *JNO8(u8 to);
|
ATTR_DEP extern u8* JNO8(u8 to);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// jb rel16
|
// jb rel16
|
||||||
|
@ -103,44 +103,44 @@ ATTR_DEP extern u16* JZ16( u16 to );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// jns rel32
|
// jns rel32
|
||||||
ATTR_DEP extern u32 *JNS32(u32 to);
|
ATTR_DEP extern u32* JNS32(u32 to);
|
||||||
// js rel32
|
// js rel32
|
||||||
ATTR_DEP extern u32 *JS32(u32 to);
|
ATTR_DEP extern u32* JS32(u32 to);
|
||||||
|
|
||||||
// jb rel32
|
// jb rel32
|
||||||
ATTR_DEP extern u32 *JB32(u32 to);
|
ATTR_DEP extern u32* JB32(u32 to);
|
||||||
// je rel32
|
// je rel32
|
||||||
ATTR_DEP extern u32 *JE32(u32 to);
|
ATTR_DEP extern u32* JE32(u32 to);
|
||||||
// jz rel32
|
// jz rel32
|
||||||
ATTR_DEP extern u32 *JZ32(u32 to);
|
ATTR_DEP extern u32* JZ32(u32 to);
|
||||||
// jg rel32
|
// jg rel32
|
||||||
ATTR_DEP extern u32 *JG32(u32 to);
|
ATTR_DEP extern u32* JG32(u32 to);
|
||||||
// jge rel32
|
// jge rel32
|
||||||
ATTR_DEP extern u32 *JGE32(u32 to);
|
ATTR_DEP extern u32* JGE32(u32 to);
|
||||||
// jl rel32
|
// jl rel32
|
||||||
ATTR_DEP extern u32 *JL32(u32 to);
|
ATTR_DEP extern u32* JL32(u32 to);
|
||||||
// jle rel32
|
// jle rel32
|
||||||
ATTR_DEP extern u32 *JLE32(u32 to);
|
ATTR_DEP extern u32* JLE32(u32 to);
|
||||||
// jae rel32
|
// jae rel32
|
||||||
ATTR_DEP extern u32 *JAE32(u32 to);
|
ATTR_DEP extern u32* JAE32(u32 to);
|
||||||
// jne rel32
|
// jne rel32
|
||||||
ATTR_DEP extern u32 *JNE32(u32 to);
|
ATTR_DEP extern u32* JNE32(u32 to);
|
||||||
// jnz rel32
|
// jnz rel32
|
||||||
ATTR_DEP extern u32 *JNZ32(u32 to);
|
ATTR_DEP extern u32* JNZ32(u32 to);
|
||||||
// jng rel32
|
// jng rel32
|
||||||
ATTR_DEP extern u32 *JNG32(u32 to);
|
ATTR_DEP extern u32* JNG32(u32 to);
|
||||||
// jnge rel32
|
// jnge rel32
|
||||||
ATTR_DEP extern u32 *JNGE32(u32 to);
|
ATTR_DEP extern u32* JNGE32(u32 to);
|
||||||
// jnl rel32
|
// jnl rel32
|
||||||
ATTR_DEP extern u32 *JNL32(u32 to);
|
ATTR_DEP extern u32* JNL32(u32 to);
|
||||||
// jnle rel32
|
// jnle rel32
|
||||||
ATTR_DEP extern u32 *JNLE32(u32 to);
|
ATTR_DEP extern u32* JNLE32(u32 to);
|
||||||
// jo rel32
|
// jo rel32
|
||||||
ATTR_DEP extern u32 *JO32(u32 to);
|
ATTR_DEP extern u32* JO32(u32 to);
|
||||||
// jno rel32
|
// jno rel32
|
||||||
ATTR_DEP extern u32 *JNO32(u32 to);
|
ATTR_DEP extern u32* JNO32(u32 to);
|
||||||
// js rel32
|
// js rel32
|
||||||
ATTR_DEP extern u32 *JS32(u32 to);
|
ATTR_DEP extern u32* JS32(u32 to);
|
||||||
|
|
||||||
//******************
|
//******************
|
||||||
// FPU instructions
|
// FPU instructions
|
||||||
|
|
|
@ -36,5 +36,5 @@ using x86Emitter::xWrite64;
|
||||||
extern void ModRM(uint mod, uint reg, uint rm);
|
extern void ModRM(uint mod, uint reg, uint rm);
|
||||||
extern void SibSB(uint ss, uint index, uint base);
|
extern void SibSB(uint ss, uint index, uint base);
|
||||||
extern void SET8R(int cc, int to);
|
extern void SET8R(int cc, int to);
|
||||||
extern u8 *J8Rel(int cc, int to);
|
extern u8* J8Rel(int cc, int to);
|
||||||
extern u32 *J32Rel(int cc, u32 to);
|
extern u32* J32Rel(int cc, u32 to);
|
||||||
|
|
|
@ -34,132 +34,146 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from)
|
void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from)
|
||||||
{
|
{
|
||||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||||
|
|
||||||
if (to == from)
|
if (to == from)
|
||||||
return; // ignore redundant MOVs.
|
return; // ignore redundant MOVs.
|
||||||
|
|
||||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
|
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Mov::operator()(const xRegisterInt &to, const xRegisterInt &from) const
|
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
|
||||||
{
|
{
|
||||||
// FIXME WTF?
|
// FIXME WTF?
|
||||||
_xMovRtoR(to, from);
|
_xMovRtoR(to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Mov::operator()(const xIndirectVoid &dest, const xRegisterInt &from) const
|
void xImpl_Mov::operator()(const xIndirectVoid& dest, const xRegisterInt& from) const
|
||||||
{
|
{
|
||||||
// mov eax has a special from when writing directly to a DISP32 address
|
// mov eax has a special from when writing directly to a DISP32 address
|
||||||
// (sans any register index/base registers).
|
// (sans any register index/base registers).
|
||||||
|
|
||||||
#ifndef __M_X86_64
|
#ifndef __M_X86_64
|
||||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||||
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty()) {
|
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty())
|
||||||
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
{
|
||||||
xWrite32(dest.Displacement);
|
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
||||||
} else
|
xWrite32(dest.Displacement);
|
||||||
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) const
|
void xImpl_Mov::operator()(const xRegisterInt& to, const xIndirectVoid& src) const
|
||||||
{
|
{
|
||||||
// mov eax has a special from when reading directly from a DISP32 address
|
// mov eax has a special from when reading directly from a DISP32 address
|
||||||
// (sans any register index/base registers).
|
// (sans any register index/base registers).
|
||||||
|
|
||||||
#ifndef __M_X86_64
|
#ifndef __M_X86_64
|
||||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||||
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty()) {
|
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty())
|
||||||
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
{
|
||||||
xWrite32(src.Displacement);
|
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
||||||
} else
|
xWrite32(src.Displacement);
|
||||||
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_Mov::operator()(const xIndirect64orLess &dest, sptr imm) const
|
void xImpl_Mov::operator()(const xIndirect64orLess& dest, sptr imm) const
|
||||||
{
|
{
|
||||||
switch (dest.GetOperandSize()) {
|
switch (dest.GetOperandSize())
|
||||||
case 1:
|
{
|
||||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
case 1:
|
||||||
break;
|
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||||
case 2:
|
break;
|
||||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
case 2:
|
||||||
break;
|
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||||
case 4:
|
break;
|
||||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
case 4:
|
||||||
break;
|
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||||
case 8:
|
break;
|
||||||
pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!");
|
case 8:
|
||||||
break;
|
pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!");
|
||||||
default:
|
break;
|
||||||
pxAssertMsg(0, "Bad indirect size!");
|
default:
|
||||||
}
|
pxAssertMsg(0, "Bad indirect size!");
|
||||||
xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize());
|
}
|
||||||
dest.xWriteImm(imm);
|
xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize());
|
||||||
}
|
dest.xWriteImm(imm);
|
||||||
|
}
|
||||||
|
|
||||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||||
// the flags (namely replacing mov reg,0 with xor).
|
// the flags (namely replacing mov reg,0 with xor).
|
||||||
void xImpl_Mov::operator()(const xRegisterInt &to, sptr imm, bool preserve_flags) const
|
void xImpl_Mov::operator()(const xRegisterInt& to, sptr imm, bool preserve_flags) const
|
||||||
{
|
{
|
||||||
switch (to.GetOperandSize()) {
|
switch (to.GetOperandSize())
|
||||||
case 1:
|
{
|
||||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
case 1:
|
||||||
break;
|
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||||
case 2:
|
break;
|
||||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
case 2:
|
||||||
break;
|
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||||
case 4:
|
break;
|
||||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
case 4:
|
||||||
break;
|
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||||
case 8:
|
break;
|
||||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!");
|
case 8:
|
||||||
break;
|
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!");
|
||||||
default:
|
break;
|
||||||
pxAssertMsg(0, "Bad indirect size!");
|
default:
|
||||||
}
|
pxAssertMsg(0, "Bad indirect size!");
|
||||||
const xRegisterInt& to_ = to.GetNonWide();
|
}
|
||||||
if (!preserve_flags && (imm == 0)) {
|
const xRegisterInt& to_ = to.GetNonWide();
|
||||||
_g1_EmitOp(G1Type_XOR, to_, to_);
|
if (!preserve_flags && (imm == 0))
|
||||||
} else if (imm == (u32)imm || !to.IsWide()) {
|
{
|
||||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
_g1_EmitOp(G1Type_XOR, to_, to_);
|
||||||
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
}
|
||||||
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
else if (imm == (u32)imm || !to.IsWide())
|
||||||
to_.xWriteImm(imm);
|
{
|
||||||
} else {
|
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||||
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
||||||
to.xWriteImm(imm);
|
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
||||||
}
|
to_.xWriteImm(imm);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
||||||
|
to.xWriteImm(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const xImpl_Mov xMOV;
|
const xImpl_Mov xMOV;
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
||||||
{
|
{
|
||||||
if (imm == (u32)imm || imm == (s32)imm) {
|
if (imm == (u32)imm || imm == (s32)imm)
|
||||||
xMOV(to, imm, preserve_flags);
|
{
|
||||||
} else {
|
xMOV(to, imm, preserve_flags);
|
||||||
u8 opcode = 0xb8 | to.Id;
|
}
|
||||||
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
else
|
||||||
xWrite64(imm);
|
{
|
||||||
}
|
u8 opcode = 0xb8 | to.Id;
|
||||||
}
|
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
||||||
|
xWrite64(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const xImpl_MovImm64 xMOV64;
|
const xImpl_MovImm64 xMOV64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// CMOVcc
|
// CMOVcc
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.")
|
#define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.")
|
||||||
|
|
||||||
|
@ -169,63 +183,63 @@ const xImpl_MovImm64 xMOV64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const
|
void xImpl_CMov::operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const
|
||||||
{
|
{
|
||||||
pxAssert(to->GetOperandSize() == from->GetOperandSize());
|
pxAssert(to->GetOperandSize() == from->GetOperandSize());
|
||||||
ccSane();
|
ccSane();
|
||||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from);
|
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const
|
void xImpl_CMov::operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const
|
||||||
{
|
{
|
||||||
ccSane();
|
ccSane();
|
||||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc);
|
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||||
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||||
|
|
||||||
void xImpl_Set::operator()(const xRegister8 &to) const
|
void xImpl_Set::operator()(const xRegister8& to) const
|
||||||
{
|
{
|
||||||
ccSane();
|
ccSane();
|
||||||
xOpWrite0F(0x90 | ccType, 0, to);
|
xOpWrite0F(0x90 | ccType, 0, to);
|
||||||
}
|
}
|
||||||
void xImpl_Set::operator()(const xIndirect8 &dest) const
|
void xImpl_Set::operator()(const xIndirect8& dest) const
|
||||||
{
|
{
|
||||||
ccSane();
|
ccSane();
|
||||||
xOpWrite0F(0x90 | ccType, 0, dest);
|
xOpWrite0F(0x90 | ccType, 0, dest);
|
||||||
}
|
}
|
||||||
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
||||||
|
|
||||||
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xRegister8 &from) const
|
void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xRegister8& from) const
|
||||||
{
|
{
|
||||||
EbpAssert();
|
EbpAssert();
|
||||||
xOpWrite0F(
|
xOpWrite0F(
|
||||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||||
SignExtend ? 0xbe : 0xb6,
|
SignExtend ? 0xbe : 0xb6,
|
||||||
to, from);
|
to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const
|
void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const
|
||||||
{
|
{
|
||||||
EbpAssert();
|
EbpAssert();
|
||||||
xOpWrite0F(
|
xOpWrite0F(
|
||||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||||
SignExtend ? 0xbe : 0xb6,
|
SignExtend ? 0xbe : 0xb6,
|
||||||
to, sibsrc);
|
to, sibsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xRegister16 &from) const
|
void xImpl_MovExtend::operator()(const xRegister32or64& to, const xRegister16& from) const
|
||||||
{
|
{
|
||||||
EbpAssert();
|
EbpAssert();
|
||||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from);
|
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const
|
void xImpl_MovExtend::operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const
|
||||||
{
|
{
|
||||||
EbpAssert();
|
EbpAssert();
|
||||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc);
|
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const
|
void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const
|
||||||
|
@ -241,58 +255,58 @@ void xImpl_MovExtend::operator()( const xRegister16or32& to, const xDirectOrIndi
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const xImpl_MovExtend xMOVSX = {true};
|
const xImpl_MovExtend xMOVSX = {true};
|
||||||
const xImpl_MovExtend xMOVZX = {false};
|
const xImpl_MovExtend xMOVZX = {false};
|
||||||
|
|
||||||
const xImpl_CMov xCMOVA = {Jcc_Above};
|
const xImpl_CMov xCMOVA = {Jcc_Above};
|
||||||
const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual};
|
const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual};
|
||||||
const xImpl_CMov xCMOVB = {Jcc_Below};
|
const xImpl_CMov xCMOVB = {Jcc_Below};
|
||||||
const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual};
|
const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual};
|
||||||
|
|
||||||
const xImpl_CMov xCMOVG = {Jcc_Greater};
|
const xImpl_CMov xCMOVG = {Jcc_Greater};
|
||||||
const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual};
|
const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual};
|
||||||
const xImpl_CMov xCMOVL = {Jcc_Less};
|
const xImpl_CMov xCMOVL = {Jcc_Less};
|
||||||
const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual};
|
const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual};
|
||||||
|
|
||||||
const xImpl_CMov xCMOVZ = {Jcc_Zero};
|
const xImpl_CMov xCMOVZ = {Jcc_Zero};
|
||||||
const xImpl_CMov xCMOVE = {Jcc_Equal};
|
const xImpl_CMov xCMOVE = {Jcc_Equal};
|
||||||
const xImpl_CMov xCMOVNZ = {Jcc_NotZero};
|
const xImpl_CMov xCMOVNZ = {Jcc_NotZero};
|
||||||
const xImpl_CMov xCMOVNE = {Jcc_NotEqual};
|
const xImpl_CMov xCMOVNE = {Jcc_NotEqual};
|
||||||
|
|
||||||
const xImpl_CMov xCMOVO = {Jcc_Overflow};
|
const xImpl_CMov xCMOVO = {Jcc_Overflow};
|
||||||
const xImpl_CMov xCMOVNO = {Jcc_NotOverflow};
|
const xImpl_CMov xCMOVNO = {Jcc_NotOverflow};
|
||||||
const xImpl_CMov xCMOVC = {Jcc_Carry};
|
const xImpl_CMov xCMOVC = {Jcc_Carry};
|
||||||
const xImpl_CMov xCMOVNC = {Jcc_NotCarry};
|
const xImpl_CMov xCMOVNC = {Jcc_NotCarry};
|
||||||
|
|
||||||
const xImpl_CMov xCMOVS = {Jcc_Signed};
|
const xImpl_CMov xCMOVS = {Jcc_Signed};
|
||||||
const xImpl_CMov xCMOVNS = {Jcc_Unsigned};
|
const xImpl_CMov xCMOVNS = {Jcc_Unsigned};
|
||||||
const xImpl_CMov xCMOVPE = {Jcc_ParityEven};
|
const xImpl_CMov xCMOVPE = {Jcc_ParityEven};
|
||||||
const xImpl_CMov xCMOVPO = {Jcc_ParityOdd};
|
const xImpl_CMov xCMOVPO = {Jcc_ParityOdd};
|
||||||
|
|
||||||
|
|
||||||
const xImpl_Set xSETA = {Jcc_Above};
|
const xImpl_Set xSETA = {Jcc_Above};
|
||||||
const xImpl_Set xSETAE = {Jcc_AboveOrEqual};
|
const xImpl_Set xSETAE = {Jcc_AboveOrEqual};
|
||||||
const xImpl_Set xSETB = {Jcc_Below};
|
const xImpl_Set xSETB = {Jcc_Below};
|
||||||
const xImpl_Set xSETBE = {Jcc_BelowOrEqual};
|
const xImpl_Set xSETBE = {Jcc_BelowOrEqual};
|
||||||
|
|
||||||
const xImpl_Set xSETG = {Jcc_Greater};
|
const xImpl_Set xSETG = {Jcc_Greater};
|
||||||
const xImpl_Set xSETGE = {Jcc_GreaterOrEqual};
|
const xImpl_Set xSETGE = {Jcc_GreaterOrEqual};
|
||||||
const xImpl_Set xSETL = {Jcc_Less};
|
const xImpl_Set xSETL = {Jcc_Less};
|
||||||
const xImpl_Set xSETLE = {Jcc_LessOrEqual};
|
const xImpl_Set xSETLE = {Jcc_LessOrEqual};
|
||||||
|
|
||||||
const xImpl_Set xSETZ = {Jcc_Zero};
|
const xImpl_Set xSETZ = {Jcc_Zero};
|
||||||
const xImpl_Set xSETE = {Jcc_Equal};
|
const xImpl_Set xSETE = {Jcc_Equal};
|
||||||
const xImpl_Set xSETNZ = {Jcc_NotZero};
|
const xImpl_Set xSETNZ = {Jcc_NotZero};
|
||||||
const xImpl_Set xSETNE = {Jcc_NotEqual};
|
const xImpl_Set xSETNE = {Jcc_NotEqual};
|
||||||
|
|
||||||
const xImpl_Set xSETO = {Jcc_Overflow};
|
const xImpl_Set xSETO = {Jcc_Overflow};
|
||||||
const xImpl_Set xSETNO = {Jcc_NotOverflow};
|
const xImpl_Set xSETNO = {Jcc_NotOverflow};
|
||||||
const xImpl_Set xSETC = {Jcc_Carry};
|
const xImpl_Set xSETC = {Jcc_Carry};
|
||||||
const xImpl_Set xSETNC = {Jcc_NotCarry};
|
const xImpl_Set xSETNC = {Jcc_NotCarry};
|
||||||
|
|
||||||
const xImpl_Set xSETS = {Jcc_Signed};
|
const xImpl_Set xSETS = {Jcc_Signed};
|
||||||
const xImpl_Set xSETNS = {Jcc_Unsigned};
|
const xImpl_Set xSETNS = {Jcc_Unsigned};
|
||||||
const xImpl_Set xSETPE = {Jcc_ParityEven};
|
const xImpl_Set xSETPE = {Jcc_ParityEven};
|
||||||
const xImpl_Set xSETPO = {Jcc_ParityOdd};
|
const xImpl_Set xSETPO = {Jcc_ParityOdd};
|
||||||
|
|
||||||
} // end namespace x86Emitter
|
} // end namespace x86Emitter
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,11 @@
|
||||||
|
|
||||||
#include "common/Dependencies.h"
|
#include "common/Dependencies.h"
|
||||||
|
|
||||||
enum x86VendorType {
|
enum x86VendorType
|
||||||
x86Vendor_Intel = 0,
|
{
|
||||||
x86Vendor_AMD = 1,
|
x86Vendor_Intel = 0,
|
||||||
x86Vendor_Unknown = 2
|
x86Vendor_AMD = 1,
|
||||||
|
x86Vendor_Unknown = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -29,117 +30,120 @@ enum x86VendorType {
|
||||||
class x86capabilities
|
class x86capabilities
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool isIdentified;
|
bool isIdentified;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
x86VendorType VendorID;
|
x86VendorType VendorID;
|
||||||
|
|
||||||
uint FamilyID; // Processor Family
|
uint FamilyID; // Processor Family
|
||||||
uint Model; // Processor Model
|
uint Model; // Processor Model
|
||||||
uint TypeID; // Processor Type
|
uint TypeID; // Processor Type
|
||||||
uint StepID; // Stepping ID
|
uint StepID; // Stepping ID
|
||||||
|
|
||||||
u32 Flags; // Feature Flags
|
u32 Flags; // Feature Flags
|
||||||
u32 Flags2; // More Feature Flags
|
u32 Flags2; // More Feature Flags
|
||||||
u32 EFlags; // Extended Feature Flags
|
u32 EFlags; // Extended Feature Flags
|
||||||
u32 EFlags2; // Extended Feature Flags pg2
|
u32 EFlags2; // Extended Feature Flags pg2
|
||||||
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
||||||
|
|
||||||
char VendorName[16]; // Vendor/Creator ID
|
char VendorName[16]; // Vendor/Creator ID
|
||||||
char FamilyName[50]; // the original cpu name
|
char FamilyName[50]; // the original cpu name
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// x86 CPU Capabilities Section (all boolean flags!)
|
// x86 CPU Capabilities Section (all boolean flags!)
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u32 hasFloatingPointUnit : 1;
|
u32 hasFloatingPointUnit : 1;
|
||||||
u32 hasVirtual8086ModeEnhancements : 1;
|
u32 hasVirtual8086ModeEnhancements : 1;
|
||||||
u32 hasDebuggingExtensions : 1;
|
u32 hasDebuggingExtensions : 1;
|
||||||
u32 hasPageSizeExtensions : 1;
|
u32 hasPageSizeExtensions : 1;
|
||||||
u32 hasTimeStampCounter : 1;
|
u32 hasTimeStampCounter : 1;
|
||||||
u32 hasModelSpecificRegisters : 1;
|
u32 hasModelSpecificRegisters : 1;
|
||||||
u32 hasPhysicalAddressExtension : 1;
|
u32 hasPhysicalAddressExtension : 1;
|
||||||
u32 hasCOMPXCHG8BInstruction : 1;
|
u32 hasCOMPXCHG8BInstruction : 1;
|
||||||
u32 hasAdvancedProgrammableInterruptController : 1;
|
u32 hasAdvancedProgrammableInterruptController : 1;
|
||||||
u32 hasSEPFastSystemCall : 1;
|
u32 hasSEPFastSystemCall : 1;
|
||||||
u32 hasMemoryTypeRangeRegisters : 1;
|
u32 hasMemoryTypeRangeRegisters : 1;
|
||||||
u32 hasPTEGlobalFlag : 1;
|
u32 hasPTEGlobalFlag : 1;
|
||||||
u32 hasMachineCheckArchitecture : 1;
|
u32 hasMachineCheckArchitecture : 1;
|
||||||
u32 hasConditionalMoveAndCompareInstructions : 1;
|
u32 hasConditionalMoveAndCompareInstructions : 1;
|
||||||
u32 hasFGPageAttributeTable : 1;
|
u32 hasFGPageAttributeTable : 1;
|
||||||
u32 has36bitPageSizeExtension : 1;
|
u32 has36bitPageSizeExtension : 1;
|
||||||
u32 hasProcessorSerialNumber : 1;
|
u32 hasProcessorSerialNumber : 1;
|
||||||
u32 hasCFLUSHInstruction : 1;
|
u32 hasCFLUSHInstruction : 1;
|
||||||
u32 hasDebugStore : 1;
|
u32 hasDebugStore : 1;
|
||||||
u32 hasACPIThermalMonitorAndClockControl : 1;
|
u32 hasACPIThermalMonitorAndClockControl : 1;
|
||||||
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
|
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
|
||||||
u32 hasStreamingSIMDExtensions : 1;
|
u32 hasStreamingSIMDExtensions : 1;
|
||||||
u32 hasStreamingSIMD2Extensions : 1;
|
u32 hasStreamingSIMD2Extensions : 1;
|
||||||
u32 hasSelfSnoop : 1;
|
u32 hasSelfSnoop : 1;
|
||||||
|
|
||||||
// is TRUE for both multi-core and Hyperthreaded CPUs.
|
// is TRUE for both multi-core and Hyperthreaded CPUs.
|
||||||
u32 hasMultiThreading : 1;
|
u32 hasMultiThreading : 1;
|
||||||
|
|
||||||
u32 hasThermalMonitor : 1;
|
u32 hasThermalMonitor : 1;
|
||||||
u32 hasIntel64BitArchitecture : 1;
|
u32 hasIntel64BitArchitecture : 1;
|
||||||
u32 hasStreamingSIMD3Extensions : 1;
|
u32 hasStreamingSIMD3Extensions : 1;
|
||||||
u32 hasSupplementalStreamingSIMD3Extensions : 1;
|
u32 hasSupplementalStreamingSIMD3Extensions : 1;
|
||||||
u32 hasStreamingSIMD4Extensions : 1;
|
u32 hasStreamingSIMD4Extensions : 1;
|
||||||
u32 hasStreamingSIMD4Extensions2 : 1;
|
u32 hasStreamingSIMD4Extensions2 : 1;
|
||||||
u32 hasAVX : 1;
|
u32 hasAVX : 1;
|
||||||
u32 hasAVX2 : 1;
|
u32 hasAVX2 : 1;
|
||||||
u32 hasBMI1 : 1;
|
u32 hasBMI1 : 1;
|
||||||
u32 hasBMI2 : 1;
|
u32 hasBMI2 : 1;
|
||||||
u32 hasFMA : 1;
|
u32 hasFMA : 1;
|
||||||
|
|
||||||
// AMD-specific CPU Features
|
// AMD-specific CPU Features
|
||||||
u32 hasAMD64BitArchitecture : 1;
|
u32 hasAMD64BitArchitecture : 1;
|
||||||
u32 hasStreamingSIMD4ExtensionsA : 1;
|
u32 hasStreamingSIMD4ExtensionsA : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 AllCapabilities;
|
u64 AllCapabilities;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Core Counts!
|
// Core Counts!
|
||||||
u32 PhysicalCores;
|
u32 PhysicalCores;
|
||||||
u32 LogicalCores;
|
u32 LogicalCores;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
x86capabilities();
|
x86capabilities();
|
||||||
|
|
||||||
void Identify();
|
void Identify();
|
||||||
void CountCores();
|
void CountCores();
|
||||||
wxString GetTypeName() const;
|
wxString GetTypeName() const;
|
||||||
|
|
||||||
u32 CalculateMHz() const;
|
u32 CalculateMHz() const;
|
||||||
|
|
||||||
void SIMD_EstablishMXCSRmask();
|
void SIMD_EstablishMXCSRmask();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
s64 _CPUSpeedHz(u64 time) const;
|
s64 _CPUSpeedHz(u64 time) const;
|
||||||
void CountLogicalCores();
|
void CountLogicalCores();
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SSE_RoundMode {
|
enum SSE_RoundMode
|
||||||
SSE_RoundMode_FIRST = 0,
|
{
|
||||||
SSEround_Nearest = 0,
|
SSE_RoundMode_FIRST = 0,
|
||||||
SSEround_NegInf,
|
SSEround_Nearest = 0,
|
||||||
SSEround_PosInf,
|
SSEround_NegInf,
|
||||||
SSEround_Chop,
|
SSEround_PosInf,
|
||||||
SSE_RoundMode_COUNT
|
SSEround_Chop,
|
||||||
|
SSE_RoundMode_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
ImplementEnumOperators(SSE_RoundMode);
|
ImplementEnumOperators(SSE_RoundMode);
|
||||||
|
|
||||||
// Predeclaration for xIndirect32
|
// Predeclaration for xIndirect32
|
||||||
namespace x86Emitter {
|
namespace x86Emitter
|
||||||
template <typename T> class xIndirect;
|
{
|
||||||
|
template <typename T>
|
||||||
|
class xIndirect;
|
||||||
typedef xIndirect<u32> xIndirect32;
|
typedef xIndirect<u32> xIndirect32;
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SSE_MXCSR - Control/Status Register (bitfield)
|
// SSE_MXCSR - Control/Status Register (bitfield)
|
||||||
|
@ -153,52 +157,52 @@ namespace x86Emitter {
|
||||||
//
|
//
|
||||||
union SSE_MXCSR
|
union SSE_MXCSR
|
||||||
{
|
{
|
||||||
u32 bitmask;
|
u32 bitmask;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u32
|
u32
|
||||||
InvalidOpFlag : 1,
|
InvalidOpFlag : 1,
|
||||||
DenormalFlag : 1,
|
DenormalFlag : 1,
|
||||||
DivideByZeroFlag : 1,
|
DivideByZeroFlag : 1,
|
||||||
OverflowFlag : 1,
|
OverflowFlag : 1,
|
||||||
UnderflowFlag : 1,
|
UnderflowFlag : 1,
|
||||||
PrecisionFlag : 1,
|
PrecisionFlag : 1,
|
||||||
|
|
||||||
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
|
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
|
||||||
// SSE1 cpus will result in an invalid instruction exception when executing
|
// SSE1 cpus will result in an invalid instruction exception when executing
|
||||||
// LDMXSCR.
|
// LDMXSCR.
|
||||||
DenormalsAreZero : 1,
|
DenormalsAreZero : 1,
|
||||||
|
|
||||||
InvalidOpMask : 1,
|
InvalidOpMask : 1,
|
||||||
DenormalMask : 1,
|
DenormalMask : 1,
|
||||||
DivideByZeroMask : 1,
|
DivideByZeroMask : 1,
|
||||||
OverflowMask : 1,
|
OverflowMask : 1,
|
||||||
UnderflowMask : 1,
|
UnderflowMask : 1,
|
||||||
PrecisionMask : 1,
|
PrecisionMask : 1,
|
||||||
|
|
||||||
RoundingControl : 2,
|
RoundingControl : 2,
|
||||||
FlushToZero : 1;
|
FlushToZero : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
SSE_RoundMode GetRoundMode() const;
|
SSE_RoundMode GetRoundMode() const;
|
||||||
SSE_MXCSR &SetRoundMode(SSE_RoundMode mode);
|
SSE_MXCSR& SetRoundMode(SSE_RoundMode mode);
|
||||||
SSE_MXCSR &ClearExceptionFlags();
|
SSE_MXCSR& ClearExceptionFlags();
|
||||||
SSE_MXCSR &EnableExceptions();
|
SSE_MXCSR& EnableExceptions();
|
||||||
SSE_MXCSR &DisableExceptions();
|
SSE_MXCSR& DisableExceptions();
|
||||||
|
|
||||||
SSE_MXCSR &ApplyReserveMask();
|
SSE_MXCSR& ApplyReserveMask();
|
||||||
|
|
||||||
bool operator==(const SSE_MXCSR &right) const
|
bool operator==(const SSE_MXCSR& right) const
|
||||||
{
|
{
|
||||||
return bitmask == right.bitmask;
|
return bitmask == right.bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const SSE_MXCSR &right) const
|
bool operator!=(const SSE_MXCSR& right) const
|
||||||
{
|
{
|
||||||
return bitmask != right.bitmask;
|
return bitmask != right.bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator x86Emitter::xIndirect32() const;
|
operator x86Emitter::xIndirect32() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SSE_MXCSR MXCSR_Mask;
|
extern SSE_MXCSR MXCSR_Mask;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -22,115 +22,117 @@ using namespace pxSizerFlags;
|
||||||
// pxCheckBox Implementations
|
// pxCheckBox Implementations
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext, int flags)
|
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext, int flags)
|
||||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||||
{
|
{
|
||||||
Init(label, subtext, flags);
|
Init(label, subtext, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, int flags)
|
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, int flags)
|
||||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||||
{
|
{
|
||||||
Init(label, wxEmptyString, flags);
|
Init(label, wxEmptyString, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxCheckBox::Init(const wxString &label, const wxString &subtext, int flags)
|
void pxCheckBox::Init(const wxString& label, const wxString& subtext, int flags)
|
||||||
{
|
{
|
||||||
m_subtext = NULL;
|
m_subtext = NULL;
|
||||||
m_subPadding = StdPadding * 2;
|
m_subPadding = StdPadding * 2;
|
||||||
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
|
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
|
||||||
|
|
||||||
*this += m_checkbox | pxSizerFlags::StdExpand();
|
*this += m_checkbox | pxSizerFlags::StdExpand();
|
||||||
|
|
||||||
static const int Indentation = 23;
|
static const int Indentation = 23;
|
||||||
if (!subtext.IsEmpty()) {
|
if (!subtext.IsEmpty())
|
||||||
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
{
|
||||||
|
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
||||||
|
|
||||||
wxFlexGridSizer &spaced(*new wxFlexGridSizer(3));
|
wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
|
||||||
spaced.AddGrowableCol(1);
|
spaced.AddGrowableCol(1);
|
||||||
spaced += Indentation;
|
spaced += Indentation;
|
||||||
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
|
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
|
||||||
//spaced += pxSizerFlags::StdPadding;
|
//spaced += pxSizerFlags::StdPadding;
|
||||||
|
|
||||||
*this += &spaced | pxExpand;
|
*this += &spaced | pxExpand;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId());
|
Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
pxCheckBox &pxCheckBox::SetSubPadding(int pad)
|
pxCheckBox& pxCheckBox::SetSubPadding(int pad)
|
||||||
{
|
{
|
||||||
m_subPadding = pad;
|
m_subPadding = pad;
|
||||||
if (m_sizerItem_subtext) {
|
if (m_sizerItem_subtext)
|
||||||
m_sizerItem_subtext->SetBorder(m_subPadding);
|
{
|
||||||
Fit();
|
m_sizerItem_subtext->SetBorder(m_subPadding);
|
||||||
}
|
Fit();
|
||||||
return *this;
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// applies the tooltip to both both the checkbox and it's static subtext (if present), and
|
// applies the tooltip to both both the checkbox and it's static subtext (if present), and
|
||||||
// performs word wrapping on platforms that need it (eg mswindows).
|
// performs word wrapping on platforms that need it (eg mswindows).
|
||||||
pxCheckBox &pxCheckBox::SetToolTip(const wxString &tip)
|
pxCheckBox& pxCheckBox::SetToolTip(const wxString& tip)
|
||||||
{
|
{
|
||||||
pxSetToolTip(m_checkbox, tip);
|
pxSetToolTip(m_checkbox, tip);
|
||||||
pxSetToolTip(m_subtext, tip);
|
pxSetToolTip(m_subtext, tip);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxCheckBox &pxCheckBox::SetValue(bool val)
|
pxCheckBox& pxCheckBox::SetValue(bool val)
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox);
|
pxAssert(m_checkbox);
|
||||||
m_checkbox->SetValue(val);
|
m_checkbox->SetValue(val);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxCheckBox &pxCheckBox::SetIndeterminate()
|
pxCheckBox& pxCheckBox::SetIndeterminate()
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox);
|
pxAssert(m_checkbox);
|
||||||
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
|
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pxCheckBox &pxCheckBox::SetState(wxCheckBoxState state)
|
pxCheckBox& pxCheckBox::SetState(wxCheckBoxState state)
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox);
|
pxAssert(m_checkbox);
|
||||||
m_checkbox->Set3StateValue(state);
|
m_checkbox->Set3StateValue(state);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forwards checkbox actions on the internal checkbox (called 'checkpart') to listeners
|
// Forwards checkbox actions on the internal checkbox (called 'checkpart') to listeners
|
||||||
// bound to the pxCheckBox "parent" panel. This helps the pxCheckBox behave more like a
|
// bound to the pxCheckBox "parent" panel. This helps the pxCheckBox behave more like a
|
||||||
// traditional checkbox.
|
// traditional checkbox.
|
||||||
void pxCheckBox::OnCheckpartCommand(wxCommandEvent &evt)
|
void pxCheckBox::OnCheckpartCommand(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
|
|
||||||
wxCommandEvent newevt(evt);
|
wxCommandEvent newevt(evt);
|
||||||
newevt.SetEventObject(this);
|
newevt.SetEventObject(this);
|
||||||
newevt.SetId(GetId());
|
newevt.SetId(GetId());
|
||||||
GetEventHandler()->ProcessEvent(newevt);
|
GetEventHandler()->ProcessEvent(newevt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxCheckBox::OnSubtextClicked(wxCommandEvent &evt)
|
void pxCheckBox::OnSubtextClicked(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
// TODO?
|
// TODO?
|
||||||
// We can enable the ability to allow clicks on the subtext desc/label to toggle
|
// We can enable the ability to allow clicks on the subtext desc/label to toggle
|
||||||
// the checkmark. Not sure if that's desirable.
|
// the checkmark. Not sure if that's desirable.
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, pxCheckBox *src)
|
void operator+=(wxSizer& target, pxCheckBox* src)
|
||||||
{
|
{
|
||||||
if (src)
|
if (src)
|
||||||
target.Add(src, pxExpand);
|
target.Add(src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, pxCheckBox &src)
|
void operator+=(wxSizer& target, pxCheckBox& src)
|
||||||
{
|
{
|
||||||
target.Add(&src, pxExpand);
|
target.Add(&src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer *target, pxCheckBox &src)
|
void operator+=(wxSizer* target, pxCheckBox& src)
|
||||||
{
|
{
|
||||||
target->Add(&src, pxExpand);
|
target->Add(&src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,74 +29,74 @@
|
||||||
class pxCheckBox : public wxPanelWithHelpers
|
class pxCheckBox : public wxPanelWithHelpers
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxCheckBox *m_checkbox;
|
wxCheckBox* m_checkbox;
|
||||||
pxStaticText *m_subtext;
|
pxStaticText* m_subtext;
|
||||||
|
|
||||||
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
|
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
|
||||||
int m_subPadding;
|
int m_subPadding;
|
||||||
|
|
||||||
wxSizerItem *m_sizerItem_subtext;
|
wxSizerItem* m_sizerItem_subtext;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext = wxEmptyString, int flags = wxCHK_2STATE);
|
pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext = wxEmptyString, int flags = wxCHK_2STATE);
|
||||||
pxCheckBox(wxWindow *parent, const wxString &label, int flags);
|
pxCheckBox(wxWindow* parent, const wxString& label, int flags);
|
||||||
virtual ~pxCheckBox() = default;
|
virtual ~pxCheckBox() = default;
|
||||||
|
|
||||||
bool HasSubText() const { return m_subtext != NULL; }
|
bool HasSubText() const { return m_subtext != NULL; }
|
||||||
const pxStaticText *GetSubText() const { return m_subtext; }
|
const pxStaticText* GetSubText() const { return m_subtext; }
|
||||||
|
|
||||||
pxCheckBox &SetSubPadding(int pad);
|
pxCheckBox& SetSubPadding(int pad);
|
||||||
pxCheckBox &SetToolTip(const wxString &tip);
|
pxCheckBox& SetToolTip(const wxString& tip);
|
||||||
pxCheckBox &SetValue(bool val);
|
pxCheckBox& SetValue(bool val);
|
||||||
pxCheckBox &SetIndeterminate();
|
pxCheckBox& SetIndeterminate();
|
||||||
pxCheckBox &SetState(wxCheckBoxState state);
|
pxCheckBox& SetState(wxCheckBoxState state);
|
||||||
|
|
||||||
wxCheckBoxState GetState() const
|
wxCheckBoxState GetState() const
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return m_checkbox->Get3StateValue();
|
return m_checkbox->Get3StateValue();
|
||||||
}
|
}
|
||||||
bool GetValue() const
|
bool GetValue() const
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return m_checkbox->GetValue();
|
return m_checkbox->GetValue();
|
||||||
}
|
}
|
||||||
bool IsChecked() const
|
bool IsChecked() const
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return m_checkbox->IsChecked();
|
return m_checkbox->IsChecked();
|
||||||
}
|
}
|
||||||
bool IsIndeterminate() const
|
bool IsIndeterminate() const
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
|
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
|
||||||
}
|
}
|
||||||
operator wxCheckBox &()
|
operator wxCheckBox&()
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return *m_checkbox;
|
return *m_checkbox;
|
||||||
}
|
}
|
||||||
operator const wxCheckBox &() const
|
operator const wxCheckBox&() const
|
||||||
{
|
{
|
||||||
pxAssert(m_checkbox != NULL);
|
pxAssert(m_checkbox != NULL);
|
||||||
return *m_checkbox;
|
return *m_checkbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCheckBox *GetWxPtr() { return m_checkbox; }
|
wxCheckBox* GetWxPtr() { return m_checkbox; }
|
||||||
const wxCheckBox *GetWxPtr() const { return m_checkbox; }
|
const wxCheckBox* GetWxPtr() const { return m_checkbox; }
|
||||||
|
|
||||||
//wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); }
|
//wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init(const wxString &label, const wxString &subtext, int flags);
|
void Init(const wxString& label, const wxString& subtext, int flags);
|
||||||
void OnCheckpartCommand(wxCommandEvent &evt);
|
void OnCheckpartCommand(wxCommandEvent& evt);
|
||||||
void OnSubtextClicked(wxCommandEvent &evt);
|
void OnSubtextClicked(wxCommandEvent& evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void operator+=(wxSizer &target, pxCheckBox &src);
|
extern void operator+=(wxSizer& target, pxCheckBox& src);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxCheckBox> &src)
|
inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src)
|
||||||
{
|
{
|
||||||
target.Add(src.window, src.flags);
|
target.Add(src.window, src.flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,36 +31,36 @@ typedef void FnType_Void();
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class SynchronousActionState
|
class SynchronousActionState
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(SynchronousActionState);
|
DeclareNoncopyableObject(SynchronousActionState);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_posted;
|
bool m_posted;
|
||||||
Threading::Semaphore m_sema;
|
Threading::Semaphore m_sema;
|
||||||
ScopedExcept m_exception;
|
ScopedExcept m_exception;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sptr return_value;
|
sptr return_value;
|
||||||
|
|
||||||
SynchronousActionState()
|
SynchronousActionState()
|
||||||
{
|
{
|
||||||
m_posted = false;
|
m_posted = false;
|
||||||
return_value = 0;
|
return_value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SynchronousActionState() = default;
|
virtual ~SynchronousActionState() = default;
|
||||||
|
|
||||||
void SetException(const BaseException &ex);
|
void SetException(const BaseException& ex);
|
||||||
void SetException(BaseException *ex);
|
void SetException(BaseException* ex);
|
||||||
|
|
||||||
Threading::Semaphore &GetSemaphore() { return m_sema; }
|
Threading::Semaphore& GetSemaphore() { return m_sema; }
|
||||||
const Threading::Semaphore &GetSemaphore() const { return m_sema; }
|
const Threading::Semaphore& GetSemaphore() const { return m_sema; }
|
||||||
|
|
||||||
void RethrowException() const;
|
void RethrowException() const;
|
||||||
int WaitForResult();
|
int WaitForResult();
|
||||||
int WaitForResult_NoExceptions();
|
int WaitForResult_NoExceptions();
|
||||||
void PostResult(int res);
|
void PostResult(int res);
|
||||||
void ClearResult();
|
void ClearResult();
|
||||||
void PostResult();
|
void PostResult();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,21 +73,21 @@ public:
|
||||||
//
|
//
|
||||||
class pxSimpleEvent : public wxEvent
|
class pxSimpleEvent : public wxEvent
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit pxSimpleEvent(int evtid = 0)
|
explicit pxSimpleEvent(int evtid = 0)
|
||||||
: wxEvent(0, evtid)
|
: wxEvent(0, evtid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSimpleEvent(wxWindowID winId, int evtid)
|
pxSimpleEvent(wxWindowID winId, int evtid)
|
||||||
: wxEvent(winId, evtid)
|
: wxEvent(winId, evtid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSimpleEvent(const pxSimpleEvent&) = default;
|
pxSimpleEvent(const pxSimpleEvent&) = default;
|
||||||
virtual wxEvent *Clone() const { return new pxSimpleEvent(*this); }
|
virtual wxEvent* Clone() const { return new pxSimpleEvent(*this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -99,41 +99,41 @@ wxDECLARE_EVENT(pxEvt_InvokeAction, pxActionEvent);
|
||||||
|
|
||||||
class pxActionEvent : public wxEvent
|
class pxActionEvent : public wxEvent
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SynchronousActionState *m_state;
|
SynchronousActionState* m_state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxActionEvent() = default;
|
virtual ~pxActionEvent() = default;
|
||||||
virtual pxActionEvent *Clone() const { return new pxActionEvent(*this); }
|
virtual pxActionEvent* Clone() const { return new pxActionEvent(*this); }
|
||||||
|
|
||||||
explicit pxActionEvent(SynchronousActionState *sema = NULL, int msgtype = pxEvt_InvokeAction);
|
explicit pxActionEvent(SynchronousActionState* sema = NULL, int msgtype = pxEvt_InvokeAction);
|
||||||
explicit pxActionEvent(SynchronousActionState &sema, int msgtype = pxEvt_InvokeAction);
|
explicit pxActionEvent(SynchronousActionState& sema, int msgtype = pxEvt_InvokeAction);
|
||||||
pxActionEvent(const pxActionEvent &src);
|
pxActionEvent(const pxActionEvent& src);
|
||||||
|
|
||||||
Threading::Semaphore *GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
|
Threading::Semaphore* GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
|
||||||
|
|
||||||
const SynchronousActionState *GetSyncState() const { return m_state; }
|
const SynchronousActionState* GetSyncState() const { return m_state; }
|
||||||
SynchronousActionState *GetSyncState() { return m_state; }
|
SynchronousActionState* GetSyncState() { return m_state; }
|
||||||
|
|
||||||
void SetSyncState(SynchronousActionState *obj) { m_state = obj; }
|
void SetSyncState(SynchronousActionState* obj) { m_state = obj; }
|
||||||
void SetSyncState(SynchronousActionState &obj) { m_state = &obj; }
|
void SetSyncState(SynchronousActionState& obj) { m_state = &obj; }
|
||||||
|
|
||||||
virtual void SetException(BaseException *ex);
|
virtual void SetException(BaseException* ex);
|
||||||
void SetException(const BaseException &ex);
|
void SetException(const BaseException& ex);
|
||||||
|
|
||||||
virtual void _DoInvokeEvent();
|
virtual void _DoInvokeEvent();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Extending classes should implement this method to perform whatever action it is
|
// Extending classes should implement this method to perform whatever action it is
|
||||||
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
|
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
|
||||||
// thread, and exceptions will be handled automatically.
|
// thread, and exceptions will be handled automatically.
|
||||||
//
|
//
|
||||||
// Exception note: exceptions are passed back to the thread that posted the event
|
// Exception note: exceptions are passed back to the thread that posted the event
|
||||||
// to the queue, when possible. If the calling thread is not blocking for a result
|
// to the queue, when possible. If the calling thread is not blocking for a result
|
||||||
// from this event, then the exception will be posted to the Main/UI thread instead.
|
// from this event, then the exception will be posted to the Main/UI thread instead.
|
||||||
virtual void InvokeEvent() {}
|
virtual void InvokeEvent() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,27 +142,27 @@ protected:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxExceptionEvent : public pxActionEvent
|
class pxExceptionEvent : public pxActionEvent
|
||||||
{
|
{
|
||||||
typedef pxActionEvent _parent;
|
typedef pxActionEvent _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BaseException *m_except;
|
BaseException* m_except;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxExceptionEvent(BaseException *ex = NULL)
|
pxExceptionEvent(BaseException* ex = NULL)
|
||||||
{
|
{
|
||||||
m_except = ex;
|
m_except = ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxExceptionEvent(const BaseException &ex);
|
pxExceptionEvent(const BaseException& ex);
|
||||||
|
|
||||||
virtual ~pxExceptionEvent()
|
virtual ~pxExceptionEvent()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual pxExceptionEvent *Clone() const { return new pxExceptionEvent(*this); }
|
virtual pxExceptionEvent* Clone() const { return new pxExceptionEvent(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InvokeEvent();
|
void InvokeEvent();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -171,29 +171,29 @@ protected:
|
||||||
|
|
||||||
class pxSynchronousCommandEvent : public wxCommandEvent
|
class pxSynchronousCommandEvent : public wxCommandEvent
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SynchronousActionState *m_sync;
|
SynchronousActionState* m_sync;
|
||||||
wxEventType m_realEvent;
|
wxEventType m_realEvent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxSynchronousCommandEvent() = default;
|
virtual ~pxSynchronousCommandEvent() = default;
|
||||||
virtual pxSynchronousCommandEvent *Clone() const { return new pxSynchronousCommandEvent(*this); }
|
virtual pxSynchronousCommandEvent* Clone() const { return new pxSynchronousCommandEvent(*this); }
|
||||||
|
|
||||||
pxSynchronousCommandEvent(SynchronousActionState *sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
pxSynchronousCommandEvent(SynchronousActionState* sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||||
pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||||
|
|
||||||
pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt);
|
pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt);
|
||||||
pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt);
|
pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt);
|
||||||
|
|
||||||
pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src);
|
pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src);
|
||||||
|
|
||||||
Threading::Semaphore *GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
|
Threading::Semaphore* GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
|
||||||
wxEventType GetRealEventType() const { return m_realEvent; }
|
wxEventType GetRealEventType() const { return m_realEvent; }
|
||||||
|
|
||||||
void SetException(BaseException *ex);
|
void SetException(BaseException* ex);
|
||||||
void SetException(const BaseException &ex);
|
void SetException(const BaseException& ex);
|
||||||
};
|
};
|
||||||
|
|
||||||
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
||||||
|
@ -203,23 +203,23 @@ wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class BaseMessageBoxEvent : public pxActionEvent
|
class BaseMessageBoxEvent : public pxActionEvent
|
||||||
{
|
{
|
||||||
typedef pxActionEvent _parent;
|
typedef pxActionEvent _parent;
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_Content;
|
wxString m_Content;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BaseMessageBoxEvent() = default;
|
virtual ~BaseMessageBoxEvent() = default;
|
||||||
virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); }
|
virtual BaseMessageBoxEvent* Clone() const { return new BaseMessageBoxEvent(*this); }
|
||||||
|
|
||||||
explicit BaseMessageBoxEvent(const wxString &content = wxEmptyString, SynchronousActionState *instdata = NULL);
|
explicit BaseMessageBoxEvent(const wxString& content = wxEmptyString, SynchronousActionState* instdata = NULL);
|
||||||
BaseMessageBoxEvent(const wxString &content, SynchronousActionState &instdata);
|
BaseMessageBoxEvent(const wxString& content, SynchronousActionState& instdata);
|
||||||
BaseMessageBoxEvent(const BaseMessageBoxEvent &event);
|
BaseMessageBoxEvent(const BaseMessageBoxEvent& event);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void InvokeEvent();
|
virtual void InvokeEvent();
|
||||||
virtual int _DoDialog() const;
|
virtual int _DoDialog() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -228,134 +228,134 @@ protected:
|
||||||
class MsgButtons
|
class MsgButtons
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
BITFIELD32()
|
BITFIELD32()
|
||||||
bool
|
bool
|
||||||
m_OK : 1,
|
m_OK : 1,
|
||||||
m_Cancel : 1,
|
m_Cancel : 1,
|
||||||
m_Yes : 1,
|
m_Yes : 1,
|
||||||
m_No : 1,
|
m_No : 1,
|
||||||
m_AllowToAll : 1,
|
m_AllowToAll : 1,
|
||||||
m_Apply : 1,
|
m_Apply : 1,
|
||||||
m_Abort : 1,
|
m_Abort : 1,
|
||||||
m_Retry : 1,
|
m_Retry : 1,
|
||||||
m_Ignore : 1,
|
m_Ignore : 1,
|
||||||
m_Reset : 1,
|
m_Reset : 1,
|
||||||
m_Close : 1;
|
m_Close : 1;
|
||||||
BITFIELD_END
|
BITFIELD_END
|
||||||
|
|
||||||
wxString m_CustomLabel;
|
wxString m_CustomLabel;
|
||||||
wxString m_CustomLabelId;
|
wxString m_CustomLabelId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MsgButtons() { bitset = 0; }
|
MsgButtons() { bitset = 0; }
|
||||||
|
|
||||||
MsgButtons &OK()
|
MsgButtons& OK()
|
||||||
{
|
{
|
||||||
m_OK = true;
|
m_OK = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Cancel()
|
MsgButtons& Cancel()
|
||||||
{
|
{
|
||||||
m_Cancel = true;
|
m_Cancel = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Apply()
|
MsgButtons& Apply()
|
||||||
{
|
{
|
||||||
m_Apply = true;
|
m_Apply = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Yes()
|
MsgButtons& Yes()
|
||||||
{
|
{
|
||||||
m_Yes = true;
|
m_Yes = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &No()
|
MsgButtons& No()
|
||||||
{
|
{
|
||||||
m_No = true;
|
m_No = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &ToAll()
|
MsgButtons& ToAll()
|
||||||
{
|
{
|
||||||
m_AllowToAll = true;
|
m_AllowToAll = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgButtons &Abort()
|
MsgButtons& Abort()
|
||||||
{
|
{
|
||||||
m_Abort = true;
|
m_Abort = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Retry()
|
MsgButtons& Retry()
|
||||||
{
|
{
|
||||||
m_Retry = true;
|
m_Retry = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Ignore()
|
MsgButtons& Ignore()
|
||||||
{
|
{
|
||||||
m_Ignore = true;
|
m_Ignore = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Reset()
|
MsgButtons& Reset()
|
||||||
{
|
{
|
||||||
m_Reset = true;
|
m_Reset = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &Close()
|
MsgButtons& Close()
|
||||||
{
|
{
|
||||||
m_Close = true;
|
m_Close = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// label - native language label displayed to user
|
// label - native language label displayed to user
|
||||||
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
|
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
|
||||||
MsgButtons &Custom(const wxString &label, const char *id)
|
MsgButtons& Custom(const wxString& label, const char* id)
|
||||||
{
|
{
|
||||||
m_CustomLabel = label;
|
m_CustomLabel = label;
|
||||||
m_CustomLabelId = fromUTF8(id);
|
m_CustomLabelId = fromUTF8(id);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgButtons &OKCancel()
|
MsgButtons& OKCancel()
|
||||||
{
|
{
|
||||||
m_OK = m_Cancel = true;
|
m_OK = m_Cancel = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
MsgButtons &YesNo()
|
MsgButtons& YesNo()
|
||||||
{
|
{
|
||||||
m_Yes = m_No = true;
|
m_Yes = m_No = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasOK() const { return m_OK; }
|
bool HasOK() const { return m_OK; }
|
||||||
bool HasCancel() const { return m_Cancel; }
|
bool HasCancel() const { return m_Cancel; }
|
||||||
bool HasApply() const { return m_Apply; }
|
bool HasApply() const { return m_Apply; }
|
||||||
bool HasYes() const { return m_Yes; }
|
bool HasYes() const { return m_Yes; }
|
||||||
bool HasNo() const { return m_No; }
|
bool HasNo() const { return m_No; }
|
||||||
bool AllowsToAll() const { return m_AllowToAll; }
|
bool AllowsToAll() const { return m_AllowToAll; }
|
||||||
|
|
||||||
bool HasAbort() const { return m_Abort; }
|
bool HasAbort() const { return m_Abort; }
|
||||||
bool HasRetry() const { return m_Retry; }
|
bool HasRetry() const { return m_Retry; }
|
||||||
bool HasIgnore() const { return m_Ignore; }
|
bool HasIgnore() const { return m_Ignore; }
|
||||||
bool HasReset() const { return m_Reset; }
|
bool HasReset() const { return m_Reset; }
|
||||||
bool HasClose() const { return m_Close; }
|
bool HasClose() const { return m_Close; }
|
||||||
|
|
||||||
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
|
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
|
||||||
const wxString &GetCustomLabel() const { return m_CustomLabel; }
|
const wxString& GetCustomLabel() const { return m_CustomLabel; }
|
||||||
const wxString &GetCustomLabelId() const { return m_CustomLabelId; }
|
const wxString& GetCustomLabelId() const { return m_CustomLabelId; }
|
||||||
|
|
||||||
bool Allows(wxWindowID id) const;
|
bool Allows(wxWindowID id) const;
|
||||||
void SetBestFocus(wxWindow *dialog) const;
|
void SetBestFocus(wxWindow* dialog) const;
|
||||||
void SetBestFocus(wxWindow &dialog) const;
|
void SetBestFocus(wxWindow& dialog) const;
|
||||||
|
|
||||||
bool operator==(const MsgButtons &right) const
|
bool operator==(const MsgButtons& right) const
|
||||||
{
|
{
|
||||||
return OpEqu(bitset);
|
return OpEqu(bitset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const MsgButtons &right) const
|
bool operator!=(const MsgButtons& right) const
|
||||||
{
|
{
|
||||||
return !OpEqu(bitset);
|
return !OpEqu(bitset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -378,24 +378,24 @@ public:
|
||||||
//
|
//
|
||||||
class pxMessageBoxEvent : public BaseMessageBoxEvent
|
class pxMessageBoxEvent : public BaseMessageBoxEvent
|
||||||
{
|
{
|
||||||
typedef BaseMessageBoxEvent _parent;
|
typedef BaseMessageBoxEvent _parent;
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_Title;
|
wxString m_Title;
|
||||||
MsgButtons m_Buttons;
|
MsgButtons m_Buttons;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxMessageBoxEvent() = default;
|
virtual ~pxMessageBoxEvent() = default;
|
||||||
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
virtual pxMessageBoxEvent* Clone() const { return new pxMessageBoxEvent(*this); }
|
||||||
|
|
||||||
pxMessageBoxEvent() {}
|
pxMessageBoxEvent() {}
|
||||||
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState &instdata);
|
pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState& instdata);
|
||||||
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState *instdata = NULL);
|
pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState* instdata = NULL);
|
||||||
pxMessageBoxEvent(const pxMessageBoxEvent &event) = default;
|
pxMessageBoxEvent(const pxMessageBoxEvent& event) = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int _DoDialog() const;
|
int _DoDialog() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -403,22 +403,22 @@ protected:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxAssertionEvent : public BaseMessageBoxEvent
|
class pxAssertionEvent : public BaseMessageBoxEvent
|
||||||
{
|
{
|
||||||
typedef BaseMessageBoxEvent _parent;
|
typedef BaseMessageBoxEvent _parent;
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_Stacktrace;
|
wxString m_Stacktrace;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxAssertionEvent() = default;
|
virtual ~pxAssertionEvent() = default;
|
||||||
virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); }
|
virtual pxAssertionEvent* Clone() const { return new pxAssertionEvent(*this); }
|
||||||
|
|
||||||
pxAssertionEvent(const wxString &content = wxEmptyString, const wxString &trace = wxEmptyString, SynchronousActionState *instdata = NULL);
|
pxAssertionEvent(const wxString& content = wxEmptyString, const wxString& trace = wxEmptyString, SynchronousActionState* instdata = NULL);
|
||||||
pxAssertionEvent(const wxString &content, const wxString &trace, SynchronousActionState &instdata);
|
pxAssertionEvent(const wxString& content, const wxString& trace, SynchronousActionState& instdata);
|
||||||
pxAssertionEvent(const pxAssertionEvent &event) = default;
|
pxAssertionEvent(const pxAssertionEvent& event) = default;
|
||||||
|
|
||||||
pxAssertionEvent &SetStacktrace(const wxString &trace);
|
pxAssertionEvent& SetStacktrace(const wxString& trace);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int _DoDialog() const;
|
int _DoDialog() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,12 +40,12 @@ extern const wxPoint wxDefaultPosition;
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Semaphore;
|
class Semaphore;
|
||||||
class pxThread;
|
class pxThread;
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
class BaseException;
|
class BaseException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,232 +24,239 @@ template class SafeArray<RadioPanelObjects>;
|
||||||
// ===========================================================================================
|
// ===========================================================================================
|
||||||
|
|
||||||
#define VerifyRealizedState() \
|
#define VerifyRealizedState() \
|
||||||
pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.")
|
pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.")
|
||||||
|
|
||||||
void pxRadioPanel::Init(const RadioPanelItem *srcArray, int arrsize)
|
void pxRadioPanel::Init(const RadioPanelItem* srcArray, int arrsize)
|
||||||
{
|
{
|
||||||
m_DefaultIdx = -1;
|
m_DefaultIdx = -1;
|
||||||
m_IsRealized = false;
|
m_IsRealized = false;
|
||||||
|
|
||||||
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
|
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
|
||||||
m_Indentation = 23;
|
m_Indentation = 23;
|
||||||
|
|
||||||
for (int i = 0; i < arrsize; ++i)
|
for (int i = 0; i < arrsize; ++i)
|
||||||
Append(srcArray[i]);
|
Append(srcArray[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel &pxRadioPanel::Append(const RadioPanelItem &entry)
|
pxRadioPanel& pxRadioPanel::Append(const RadioPanelItem& entry)
|
||||||
{
|
{
|
||||||
m_buttonStrings.push_back(entry);
|
m_buttonStrings.push_back(entry);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxRadioPanel::Reset()
|
void pxRadioPanel::Reset()
|
||||||
{
|
{
|
||||||
m_IsRealized = false;
|
m_IsRealized = false;
|
||||||
const int numbuttons = m_buttonStrings.size();
|
const int numbuttons = m_buttonStrings.size();
|
||||||
if (numbuttons == 0)
|
if (numbuttons == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
safe_delete(m_objects[i].LabelObj);
|
{
|
||||||
safe_delete(m_objects[i].SubTextObj);
|
safe_delete(m_objects[i].LabelObj);
|
||||||
}
|
safe_delete(m_objects[i].SubTextObj);
|
||||||
m_buttonStrings.clear();
|
}
|
||||||
|
m_buttonStrings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxRadioPanel::Realize()
|
void pxRadioPanel::Realize()
|
||||||
{
|
{
|
||||||
const int numbuttons = m_buttonStrings.size();
|
const int numbuttons = m_buttonStrings.size();
|
||||||
if (numbuttons == 0)
|
if (numbuttons == 0)
|
||||||
return;
|
return;
|
||||||
if (m_IsRealized)
|
if (m_IsRealized)
|
||||||
return;
|
return;
|
||||||
m_IsRealized = true;
|
m_IsRealized = true;
|
||||||
|
|
||||||
m_objects.MakeRoomFor(numbuttons);
|
m_objects.MakeRoomFor(numbuttons);
|
||||||
|
|
||||||
// Add all RadioButtons in one pass, and then go back and create all the subtext
|
// Add all RadioButtons in one pass, and then go back and create all the subtext
|
||||||
// objects. This ensures the radio buttons have consecutive tab order IDs, which
|
// objects. This ensures the radio buttons have consecutive tab order IDs, which
|
||||||
// is the "preferred" method when using grouping features of the native window
|
// is the "preferred" method when using grouping features of the native window
|
||||||
// managers (GTK tends to not care either way, but Win32 definitely prefers a
|
// managers (GTK tends to not care either way, but Win32 definitely prefers a
|
||||||
// linear tab order).
|
// linear tab order).
|
||||||
|
|
||||||
// first object has the group flag set to ensure it's the start of a radio group.
|
// first object has the group flag set to ensure it's the start of a radio group.
|
||||||
m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||||
for (int i = 1; i < numbuttons; ++i)
|
for (int i = 1; i < numbuttons; ++i)
|
||||||
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
m_objects[i].SubTextObj = NULL;
|
{
|
||||||
if (m_buttonStrings[i].SubText.IsEmpty())
|
m_objects[i].SubTextObj = NULL;
|
||||||
continue;
|
if (m_buttonStrings[i].SubText.IsEmpty())
|
||||||
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
|
continue;
|
||||||
}
|
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
pxAssert(GetSizer() != NULL);
|
pxAssert(GetSizer() != NULL);
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
{
|
||||||
|
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
||||||
|
|
||||||
if (pxStaticText *subobj = m_objects[i].SubTextObj) {
|
if (pxStaticText* subobj = m_objects[i].SubTextObj)
|
||||||
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
{
|
||||||
*this += 9 + m_padding.GetHeight();
|
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
||||||
}
|
*this += 9 + m_padding.GetHeight();
|
||||||
if (!m_buttonStrings[i].ToolTip.IsEmpty())
|
}
|
||||||
_setToolTipImmediate(i, m_buttonStrings[i].ToolTip);
|
if (!m_buttonStrings[i].ToolTip.IsEmpty())
|
||||||
}
|
_setToolTipImmediate(i, m_buttonStrings[i].ToolTip);
|
||||||
|
}
|
||||||
|
|
||||||
_RealizeDefaultOption();
|
_RealizeDefaultOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxRadioPanel::_setToolTipImmediate(int idx, const wxString &tip)
|
void pxRadioPanel::_setToolTipImmediate(int idx, const wxString& tip)
|
||||||
{
|
{
|
||||||
if (wxRadioButton *woot = m_objects[idx].LabelObj)
|
if (wxRadioButton* woot = m_objects[idx].LabelObj)
|
||||||
woot->SetToolTip(tip);
|
woot->SetToolTip(tip);
|
||||||
|
|
||||||
if (pxStaticText *woot = m_objects[idx].SubTextObj)
|
if (pxStaticText* woot = m_objects[idx].SubTextObj)
|
||||||
woot->SetToolTip(tip);
|
woot->SetToolTip(tip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The SetToolTip API provided by this function applies the tooltip to both the radio
|
// The SetToolTip API provided by this function applies the tooltip to both the radio
|
||||||
// button and it's static subtext (if present), and performs word wrapping on platforms
|
// button and it's static subtext (if present), and performs word wrapping on platforms
|
||||||
// that need it (eg mswindows).
|
// that need it (eg mswindows).
|
||||||
pxRadioPanel &pxRadioPanel::SetToolTip(int idx, const wxString &tip)
|
pxRadioPanel& pxRadioPanel::SetToolTip(int idx, const wxString& tip)
|
||||||
{
|
{
|
||||||
m_buttonStrings[idx].SetToolTip(tip);
|
m_buttonStrings[idx].SetToolTip(tip);
|
||||||
|
|
||||||
if (m_IsRealized)
|
if (m_IsRealized)
|
||||||
_setToolTipImmediate(idx, tip);
|
_setToolTipImmediate(idx, tip);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel &pxRadioPanel::SetSelection(int idx)
|
pxRadioPanel& pxRadioPanel::SetSelection(int idx)
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||||
m_objects[idx].LabelObj->SetValue(true);
|
m_objects[idx].LabelObj->SetValue(true);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxRadioPanel::_RealizeDefaultOption()
|
void pxRadioPanel::_RealizeDefaultOption()
|
||||||
{
|
{
|
||||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
if (m_IsRealized && m_DefaultIdx != -1)
|
||||||
wxFont def(GetFont());
|
{
|
||||||
def.SetWeight(wxFONTWEIGHT_BOLD);
|
wxFont def(GetFont());
|
||||||
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
def.SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
|
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||||
}
|
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlights (bold) the text of the default radio.
|
// Highlights (bold) the text of the default radio.
|
||||||
// Not intended for restoring default value at later time.
|
// Not intended for restoring default value at later time.
|
||||||
pxRadioPanel &pxRadioPanel::SetDefaultItem(int idx)
|
pxRadioPanel& pxRadioPanel::SetDefaultItem(int idx)
|
||||||
{
|
{
|
||||||
if (idx == m_DefaultIdx)
|
if (idx == m_DefaultIdx)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
if (m_IsRealized && m_DefaultIdx != -1)
|
||||||
wxFont def(GetFont());
|
{
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
wxFont def(GetFont());
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||||
}
|
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
||||||
|
}
|
||||||
|
|
||||||
m_DefaultIdx = idx;
|
m_DefaultIdx = idx;
|
||||||
_RealizeDefaultOption();
|
_RealizeDefaultOption();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel &pxRadioPanel::EnableItem(int idx, bool enable)
|
pxRadioPanel& pxRadioPanel::EnableItem(int idx, bool enable)
|
||||||
{
|
{
|
||||||
pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items.");
|
pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items.");
|
||||||
|
|
||||||
if (m_objects[idx].LabelObj)
|
if (m_objects[idx].LabelObj)
|
||||||
m_objects[idx].LabelObj->Enable(enable);
|
m_objects[idx].LabelObj->Enable(enable);
|
||||||
|
|
||||||
if (m_objects[idx].SubTextObj)
|
if (m_objects[idx].SubTextObj)
|
||||||
m_objects[idx].SubTextObj->Enable(enable);
|
m_objects[idx].SubTextObj->Enable(enable);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RadioPanelItem &pxRadioPanel::Item(int idx) const
|
const RadioPanelItem& pxRadioPanel::Item(int idx) const
|
||||||
{
|
{
|
||||||
return m_buttonStrings[idx];
|
return m_buttonStrings[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioPanelItem &pxRadioPanel::Item(int idx)
|
RadioPanelItem& pxRadioPanel::Item(int idx)
|
||||||
{
|
{
|
||||||
return m_buttonStrings[idx];
|
return m_buttonStrings[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
int pxRadioPanel::GetSelection() const
|
int pxRadioPanel::GetSelection() const
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (uint i = 0; i < m_buttonStrings.size(); ++i) {
|
for (uint i = 0; i < m_buttonStrings.size(); ++i)
|
||||||
if (wxRadioButton *woot = m_objects[i].LabelObj)
|
{
|
||||||
if (woot->GetValue())
|
if (wxRadioButton* woot = m_objects[i].LabelObj)
|
||||||
return i;
|
if (woot->GetValue())
|
||||||
}
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
// Technically radio buttons should never allow for a case where none are selected.
|
// Technically radio buttons should never allow for a case where none are selected.
|
||||||
// However it *can* happen on some platforms if the program code doesn't explicitly
|
// However it *can* happen on some platforms if the program code doesn't explicitly
|
||||||
// select one of the members of the group (which is, as far as I'm concerned, a
|
// select one of the members of the group (which is, as far as I'm concerned, a
|
||||||
// programmer error!). so Assert here in such cases, and return 0 as the assumed
|
// programmer error!). so Assert here in such cases, and return 0 as the assumed
|
||||||
// default, so that calling code has a "valid" return code in release builds.
|
// default, so that calling code has a "valid" return code in release builds.
|
||||||
|
|
||||||
pxFailDev("No valid selection was found in this group!");
|
pxFailDev("No valid selection was found in this group!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the wxWindowID for the currently selected radio button.
|
// Returns the wxWindowID for the currently selected radio button.
|
||||||
wxWindowID pxRadioPanel::GetSelectionId() const
|
wxWindowID pxRadioPanel::GetSelectionId() const
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return 0;
|
return 0;
|
||||||
return m_objects[GetSelection()].LabelObj->GetId();
|
return m_objects[GetSelection()].LabelObj->GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool pxRadioPanel::IsSelected(int idx) const
|
bool pxRadioPanel::IsSelected(int idx) const
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return false;
|
return false;
|
||||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||||
return m_objects[idx].LabelObj->GetValue();
|
return m_objects[idx].LabelObj->GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText *pxRadioPanel::GetSubText(int idx)
|
pxStaticText* pxRadioPanel::GetSubText(int idx)
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return NULL;
|
return NULL;
|
||||||
return m_objects[idx].SubTextObj;
|
return m_objects[idx].SubTextObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxStaticText *pxRadioPanel::GetSubText(int idx) const
|
const pxStaticText* pxRadioPanel::GetSubText(int idx) const
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return NULL;
|
return NULL;
|
||||||
return m_objects[idx].SubTextObj;
|
return m_objects[idx].SubTextObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxRadioButton *pxRadioPanel::GetButton(int idx)
|
wxRadioButton* pxRadioPanel::GetButton(int idx)
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return NULL;
|
return NULL;
|
||||||
return m_objects[idx].LabelObj;
|
return m_objects[idx].LabelObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxRadioButton *pxRadioPanel::GetButton(int idx) const
|
const wxRadioButton* pxRadioPanel::GetButton(int idx) const
|
||||||
{
|
{
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return NULL;
|
return NULL;
|
||||||
return m_objects[idx].LabelObj;
|
return m_objects[idx].LabelObj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,45 +25,45 @@
|
||||||
|
|
||||||
struct RadioPanelItem
|
struct RadioPanelItem
|
||||||
{
|
{
|
||||||
wxString Label;
|
wxString Label;
|
||||||
wxString SubText;
|
wxString SubText;
|
||||||
wxString ToolTip;
|
wxString ToolTip;
|
||||||
|
|
||||||
int SomeInt;
|
int SomeInt;
|
||||||
void *SomePtr;
|
void* SomePtr;
|
||||||
|
|
||||||
RadioPanelItem(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString)
|
RadioPanelItem(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
|
||||||
: Label(label)
|
: Label(label)
|
||||||
, SubText(subtext)
|
, SubText(subtext)
|
||||||
, ToolTip(tooltip)
|
, ToolTip(tooltip)
|
||||||
{
|
{
|
||||||
SomeInt = 0;
|
SomeInt = 0;
|
||||||
SomePtr = NULL;
|
SomePtr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioPanelItem &SetToolTip(const wxString &tip)
|
RadioPanelItem& SetToolTip(const wxString& tip)
|
||||||
{
|
{
|
||||||
ToolTip = tip;
|
ToolTip = tip;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioPanelItem &SetSubText(const wxString &text)
|
RadioPanelItem& SetSubText(const wxString& text)
|
||||||
{
|
{
|
||||||
SubText = text;
|
SubText = text;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioPanelItem &SetInt(int intval)
|
RadioPanelItem& SetInt(int intval)
|
||||||
{
|
{
|
||||||
SomeInt = intval;
|
SomeInt = intval;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioPanelItem &SetPtr(void *ptrval)
|
RadioPanelItem& SetPtr(void* ptrval)
|
||||||
{
|
{
|
||||||
SomePtr = ptrval;
|
SomePtr = ptrval;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,8 +71,8 @@ struct RadioPanelItem
|
||||||
// wrapped and re-wrapped with multiple calls to OnResize().
|
// wrapped and re-wrapped with multiple calls to OnResize().
|
||||||
struct RadioPanelObjects
|
struct RadioPanelObjects
|
||||||
{
|
{
|
||||||
wxRadioButton *LabelObj;
|
wxRadioButton* LabelObj;
|
||||||
pxStaticText *SubTextObj;
|
pxStaticText* SubTextObj;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -91,86 +91,86 @@ struct RadioPanelObjects
|
||||||
class pxRadioPanel : public wxPanelWithHelpers
|
class pxRadioPanel : public wxPanelWithHelpers
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef std::vector<RadioPanelItem> ButtonArray;
|
typedef std::vector<RadioPanelItem> ButtonArray;
|
||||||
typedef SafeArray<RadioPanelObjects> ButtonObjArray;
|
typedef SafeArray<RadioPanelObjects> ButtonObjArray;
|
||||||
|
|
||||||
ButtonArray m_buttonStrings;
|
ButtonArray m_buttonStrings;
|
||||||
ButtonObjArray m_objects;
|
ButtonObjArray m_objects;
|
||||||
|
|
||||||
bool m_IsRealized;
|
bool m_IsRealized;
|
||||||
|
|
||||||
wxSize m_padding;
|
wxSize m_padding;
|
||||||
int m_Indentation;
|
int m_Indentation;
|
||||||
int m_DefaultIdx; // index of the default option (gets specific color/font treatment)
|
int m_DefaultIdx; // index of the default option (gets specific color/font treatment)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <int size>
|
template <int size>
|
||||||
pxRadioPanel(wxWindow *parent, const RadioPanelItem (&src)[size])
|
pxRadioPanel(wxWindow* parent, const RadioPanelItem (&src)[size])
|
||||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||||
{
|
{
|
||||||
Init(src, size);
|
Init(src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel(wxWindow *parent)
|
pxRadioPanel(wxWindow* parent)
|
||||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~pxRadioPanel() = default;
|
virtual ~pxRadioPanel() = default;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void Realize();
|
void Realize();
|
||||||
|
|
||||||
pxStaticText *GetSubText(int idx);
|
pxStaticText* GetSubText(int idx);
|
||||||
const pxStaticText *GetSubText(int idx) const;
|
const pxStaticText* GetSubText(int idx) const;
|
||||||
pxRadioPanel &Append(const RadioPanelItem &entry);
|
pxRadioPanel& Append(const RadioPanelItem& entry);
|
||||||
|
|
||||||
pxRadioPanel &SetToolTip(int idx, const wxString &tip);
|
pxRadioPanel& SetToolTip(int idx, const wxString& tip);
|
||||||
pxRadioPanel &SetSelection(int idx);
|
pxRadioPanel& SetSelection(int idx);
|
||||||
pxRadioPanel &SetDefaultItem(int idx);
|
pxRadioPanel& SetDefaultItem(int idx);
|
||||||
pxRadioPanel &EnableItem(int idx, bool enable = true);
|
pxRadioPanel& EnableItem(int idx, bool enable = true);
|
||||||
|
|
||||||
const RadioPanelItem &Item(int idx) const;
|
const RadioPanelItem& Item(int idx) const;
|
||||||
RadioPanelItem &Item(int idx);
|
RadioPanelItem& Item(int idx);
|
||||||
|
|
||||||
int GetSelection() const;
|
int GetSelection() const;
|
||||||
wxWindowID GetSelectionId() const;
|
wxWindowID GetSelectionId() const;
|
||||||
bool IsSelected(int idx) const;
|
bool IsSelected(int idx) const;
|
||||||
|
|
||||||
const RadioPanelItem &SelectedItem() const { return Item(GetSelection()); }
|
const RadioPanelItem& SelectedItem() const { return Item(GetSelection()); }
|
||||||
RadioPanelItem &SelectedItem() { return Item(GetSelection()); }
|
RadioPanelItem& SelectedItem() { return Item(GetSelection()); }
|
||||||
|
|
||||||
wxRadioButton *GetButton(int idx);
|
wxRadioButton* GetButton(int idx);
|
||||||
const wxRadioButton *GetButton(int idx) const;
|
const wxRadioButton* GetButton(int idx) const;
|
||||||
|
|
||||||
int GetPaddingVert() const { return m_padding.GetHeight(); }
|
int GetPaddingVert() const { return m_padding.GetHeight(); }
|
||||||
int GetIndentation() const { return m_Indentation; }
|
int GetIndentation() const { return m_Indentation; }
|
||||||
|
|
||||||
pxRadioPanel &SetPaddingHoriz(int newpad)
|
pxRadioPanel& SetPaddingHoriz(int newpad)
|
||||||
{
|
{
|
||||||
m_padding.SetHeight(newpad);
|
m_padding.SetHeight(newpad);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel &SetIndentation(int newdent)
|
pxRadioPanel& SetIndentation(int newdent)
|
||||||
{
|
{
|
||||||
m_Indentation = newdent;
|
m_Indentation = newdent;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasSubText(int idx) const
|
bool HasSubText(int idx) const
|
||||||
{
|
{
|
||||||
return !m_buttonStrings[idx].SubText.IsEmpty();
|
return !m_buttonStrings[idx].SubText.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel &Append(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString)
|
pxRadioPanel& Append(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
|
||||||
{
|
{
|
||||||
return Append(RadioPanelItem(label, subtext, tooltip));
|
return Append(RadioPanelItem(label, subtext, tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init(const RadioPanelItem *srcArray = NULL, int arrsize = 0);
|
void Init(const RadioPanelItem* srcArray = NULL, int arrsize = 0);
|
||||||
void _setToolTipImmediate(int idx, const wxString &tip);
|
void _setToolTipImmediate(int idx, const wxString& tip);
|
||||||
void _RealizeDefaultOption();
|
void _RealizeDefaultOption();
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,33 +20,33 @@
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxStaticText (implementations)
|
// pxStaticText (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxStaticText::pxStaticText(wxWindow *parent)
|
pxStaticText::pxStaticText(wxWindow* parent)
|
||||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||||
{
|
{
|
||||||
m_align = wxALIGN_CENTRE_HORIZONTAL;
|
m_align = wxALIGN_CENTRE_HORIZONTAL;
|
||||||
m_autowrap = true;
|
m_autowrap = true;
|
||||||
m_wrappedWidth = -1;
|
m_wrappedWidth = -1;
|
||||||
m_heightInLines = 1;
|
m_heightInLines = 1;
|
||||||
|
|
||||||
SetPaddingDefaults();
|
SetPaddingDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText::pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align)
|
pxStaticText::pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align)
|
||||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||||
{
|
{
|
||||||
m_heightInLines = 1;
|
m_heightInLines = 1;
|
||||||
m_align = align;
|
m_align = align;
|
||||||
|
|
||||||
SetPaddingDefaults();
|
SetPaddingDefaults();
|
||||||
Init(label);
|
Init(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticText::Init(const wxString &label)
|
void pxStaticText::Init(const wxString& label)
|
||||||
{
|
{
|
||||||
m_autowrap = true;
|
m_autowrap = true;
|
||||||
m_wrappedWidth = -1;
|
m_wrappedWidth = -1;
|
||||||
m_label = label;
|
m_label = label;
|
||||||
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
|
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to refresh the window after changing its size as the standard
|
// we need to refresh the window after changing its size as the standard
|
||||||
|
@ -54,328 +54,338 @@ void pxStaticText::Init(const wxString &label)
|
||||||
// the control is expanded to fit -- ie the control's size changes but the position does not)
|
// the control is expanded to fit -- ie the control's size changes but the position does not)
|
||||||
void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags)
|
void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags)
|
||||||
{
|
{
|
||||||
_parent::DoSetSize(x, y, w, h, sizeFlags);
|
_parent::DoSetSize(x, y, w, h, sizeFlags);
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticText::SetPaddingDefaults()
|
void pxStaticText::SetPaddingDefaults()
|
||||||
{
|
{
|
||||||
m_paddingPix_horiz = 7;
|
m_paddingPix_horiz = 7;
|
||||||
m_paddingPix_vert = 1;
|
m_paddingPix_vert = 1;
|
||||||
|
|
||||||
m_paddingPct_horiz = 0.0f;
|
m_paddingPct_horiz = 0.0f;
|
||||||
m_paddingPct_vert = 0.0f;
|
m_paddingPct_vert = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::SetMinWidth(int width)
|
pxStaticText& pxStaticText::SetMinWidth(int width)
|
||||||
{
|
{
|
||||||
SetMinSize(wxSize(width, GetMinHeight()));
|
SetMinSize(wxSize(width, GetMinHeight()));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::SetMinHeight(int height)
|
pxStaticText& pxStaticText::SetMinHeight(int height)
|
||||||
{
|
{
|
||||||
SetMinSize(wxSize(GetMinWidth(), height));
|
SetMinSize(wxSize(GetMinWidth(), height));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::SetHeight(int lines)
|
pxStaticText& pxStaticText::SetHeight(int lines)
|
||||||
{
|
{
|
||||||
if (!pxAssert(lines > 0))
|
if (!pxAssert(lines > 0))
|
||||||
lines = 2;
|
lines = 2;
|
||||||
m_heightInLines = lines;
|
m_heightInLines = lines;
|
||||||
|
|
||||||
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
|
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
|
||||||
SetMinSize(wxSize(GetMinWidth(), newHeight));
|
SetMinSize(wxSize(GetMinWidth(), newHeight));
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::Align(wxAlignment align)
|
pxStaticText& pxStaticText::Align(wxAlignment align)
|
||||||
{
|
{
|
||||||
m_align = align;
|
m_align = align;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::Bold()
|
pxStaticText& pxStaticText::Bold()
|
||||||
{
|
{
|
||||||
wxFont bold(GetFont());
|
wxFont bold(GetFont());
|
||||||
bold.SetWeight(wxFONTWEIGHT_BOLD);
|
bold.SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
SetFont(bold);
|
SetFont(bold);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::PaddingPixH(int pixels)
|
pxStaticText& pxStaticText::PaddingPixH(int pixels)
|
||||||
{
|
{
|
||||||
m_paddingPix_horiz = pixels;
|
m_paddingPix_horiz = pixels;
|
||||||
UpdateWrapping(false);
|
UpdateWrapping(false);
|
||||||
Refresh();
|
Refresh();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::PaddingPixV(int pixels)
|
pxStaticText& pxStaticText::PaddingPixV(int pixels)
|
||||||
{
|
{
|
||||||
m_paddingPix_vert = pixels;
|
m_paddingPix_vert = pixels;
|
||||||
Refresh();
|
Refresh();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::PaddingPctH(float pct)
|
pxStaticText& pxStaticText::PaddingPctH(float pct)
|
||||||
{
|
{
|
||||||
pxAssert(pct < 0.5);
|
pxAssert(pct < 0.5);
|
||||||
|
|
||||||
m_paddingPct_horiz = pct;
|
m_paddingPct_horiz = pct;
|
||||||
UpdateWrapping(false);
|
UpdateWrapping(false);
|
||||||
Refresh();
|
Refresh();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::PaddingPctV(float pct)
|
pxStaticText& pxStaticText::PaddingPctV(float pct)
|
||||||
{
|
{
|
||||||
pxAssert(pct < 0.5);
|
pxAssert(pct < 0.5);
|
||||||
|
|
||||||
m_paddingPct_vert = pct;
|
m_paddingPct_vert = pct;
|
||||||
Refresh();
|
Refresh();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::Unwrapped()
|
pxStaticText& pxStaticText::Unwrapped()
|
||||||
{
|
{
|
||||||
m_autowrap = false;
|
m_autowrap = false;
|
||||||
UpdateWrapping(false);
|
UpdateWrapping(false);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pxStaticText::calcPaddingWidth(int newWidth) const
|
int pxStaticText::calcPaddingWidth(int newWidth) const
|
||||||
{
|
{
|
||||||
return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2);
|
return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pxStaticText::calcPaddingHeight(int newHeight) const
|
int pxStaticText::calcPaddingHeight(int newHeight) const
|
||||||
{
|
{
|
||||||
return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2);
|
return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const
|
wxSize pxStaticText::GetBestWrappedSize(const wxClientDC& dc) const
|
||||||
{
|
{
|
||||||
pxAssert(m_autowrap);
|
pxAssert(m_autowrap);
|
||||||
|
|
||||||
// Find an ideal(-ish) width, based on a search of all parent controls and their
|
// Find an ideal(-ish) width, based on a search of all parent controls and their
|
||||||
// valid Minimum sizes.
|
// valid Minimum sizes.
|
||||||
|
|
||||||
int idealWidth = wxDefaultCoord;
|
int idealWidth = wxDefaultCoord;
|
||||||
int parentalAdjust = 0;
|
int parentalAdjust = 0;
|
||||||
double parentalFactor = 1.0;
|
double parentalFactor = 1.0;
|
||||||
const wxWindow *millrun = this;
|
const wxWindow* millrun = this;
|
||||||
|
|
||||||
while (millrun) {
|
while (millrun)
|
||||||
// IMPORTANT : wxWizard changes its min size and then expects everything else
|
{
|
||||||
// to play nice and NOT resize according to the new min size. (wtf stupid)
|
// IMPORTANT : wxWizard changes its min size and then expects everything else
|
||||||
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
// to play nice and NOT resize according to the new min size. (wtf stupid)
|
||||||
if (wxIsKindOf(millrun, wxWizard))
|
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
||||||
break;
|
if (wxIsKindOf(millrun, wxWizard))
|
||||||
|
break;
|
||||||
|
|
||||||
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
||||||
|
|
||||||
if (min > 0 && ((idealWidth < 0) || (min < idealWidth))) {
|
if (min > 0 && ((idealWidth < 0) || (min < idealWidth)))
|
||||||
idealWidth = min;
|
{
|
||||||
}
|
idealWidth = min;
|
||||||
|
}
|
||||||
|
|
||||||
parentalAdjust += pxSizerFlags::StdPadding * 2;
|
parentalAdjust += pxSizerFlags::StdPadding * 2;
|
||||||
millrun = millrun->GetParent();
|
millrun = millrun->GetParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idealWidth <= 0) {
|
if (idealWidth <= 0)
|
||||||
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
|
{
|
||||||
// the size of the user's display area.
|
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
|
||||||
|
// the size of the user's display area.
|
||||||
|
|
||||||
idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2);
|
idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult());
|
return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText &pxStaticText::WrapAt(int width)
|
pxStaticText& pxStaticText::WrapAt(int width)
|
||||||
{
|
{
|
||||||
m_autowrap = false;
|
m_autowrap = false;
|
||||||
|
|
||||||
if ((width <= 1) || (width == m_wrappedWidth))
|
if ((width <= 1) || (width == m_wrappedWidth))
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
wxString wrappedLabel;
|
wxString wrappedLabel;
|
||||||
m_wrappedWidth = width;
|
m_wrappedWidth = width;
|
||||||
|
|
||||||
if (width > 1)
|
if (width > 1)
|
||||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
||||||
|
|
||||||
if (m_wrappedLabel != wrappedLabel) {
|
if (m_wrappedLabel != wrappedLabel)
|
||||||
m_wrappedLabel = wrappedLabel;
|
{
|
||||||
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
m_wrappedLabel = wrappedLabel;
|
||||||
SetMinSize(wxSize(
|
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
||||||
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
|
SetMinSize(wxSize(
|
||||||
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
|
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
|
||||||
}
|
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
|
||||||
return *this;
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxStaticText::_updateWrapping(bool textChanged)
|
bool pxStaticText::_updateWrapping(bool textChanged)
|
||||||
{
|
{
|
||||||
if (!m_autowrap) {
|
if (!m_autowrap)
|
||||||
//m_wrappedLabel = wxEmptyString;
|
{
|
||||||
//m_wrappedWidth = -1;
|
//m_wrappedLabel = wxEmptyString;
|
||||||
return false;
|
//m_wrappedWidth = -1;
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
wxString wrappedLabel;
|
wxString wrappedLabel;
|
||||||
int newWidth = GetSize().GetWidth();
|
int newWidth = GetSize().GetWidth();
|
||||||
|
|
||||||
if (!textChanged && (newWidth == m_wrappedWidth))
|
if (!textChanged && (newWidth == m_wrappedWidth))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Note: during various stages of sizer-calc, width can be 1, 0, or -1.
|
// Note: during various stages of sizer-calc, width can be 1, 0, or -1.
|
||||||
// We ignore wrapping in these cases. (the PaintEvent also checks the wrapping
|
// We ignore wrapping in these cases. (the PaintEvent also checks the wrapping
|
||||||
// and updates it if needed, in case the control's size isn't figured out prior
|
// and updates it if needed, in case the control's size isn't figured out prior
|
||||||
// to being painted).
|
// to being painted).
|
||||||
|
|
||||||
m_wrappedWidth = newWidth;
|
m_wrappedWidth = newWidth;
|
||||||
if (m_wrappedWidth > 1)
|
if (m_wrappedWidth > 1)
|
||||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
|
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
|
||||||
|
|
||||||
if (m_wrappedLabel == wrappedLabel)
|
if (m_wrappedLabel == wrappedLabel)
|
||||||
return false;
|
return false;
|
||||||
m_wrappedLabel = wrappedLabel;
|
m_wrappedLabel = wrappedLabel;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticText::UpdateWrapping(bool textChanged)
|
void pxStaticText::UpdateWrapping(bool textChanged)
|
||||||
{
|
{
|
||||||
if (_updateWrapping(textChanged))
|
if (_updateWrapping(textChanged))
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticText::SetLabel(const wxString &label)
|
void pxStaticText::SetLabel(const wxString& label)
|
||||||
{
|
{
|
||||||
const bool labelChanged(label != m_label);
|
const bool labelChanged(label != m_label);
|
||||||
if (labelChanged) {
|
if (labelChanged)
|
||||||
m_label = label;
|
{
|
||||||
Refresh();
|
m_label = label;
|
||||||
}
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
// Always update wrapping, in case window width or something else also changed.
|
// Always update wrapping, in case window width or something else also changed.
|
||||||
UpdateWrapping(labelChanged);
|
UpdateWrapping(labelChanged);
|
||||||
InvalidateBestSize();
|
InvalidateBestSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFont pxStaticText::GetFontOk() const
|
wxFont pxStaticText::GetFontOk() const
|
||||||
{
|
{
|
||||||
wxFont font(GetFont());
|
wxFont font(GetFont());
|
||||||
if (!font.Ok())
|
if (!font.Ok())
|
||||||
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxStaticText::Enable(bool enabled)
|
bool pxStaticText::Enable(bool enabled)
|
||||||
{
|
{
|
||||||
if (_parent::Enable(enabled)) {
|
if (_parent::Enable(enabled))
|
||||||
Refresh();
|
{
|
||||||
return true;
|
Refresh();
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticText::paintEvent(wxPaintEvent &evt)
|
void pxStaticText::paintEvent(wxPaintEvent& evt)
|
||||||
{
|
{
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
const int dcWidth = dc.GetSize().GetWidth();
|
const int dcWidth = dc.GetSize().GetWidth();
|
||||||
const int dcHeight = dc.GetSize().GetHeight();
|
const int dcHeight = dc.GetSize().GetHeight();
|
||||||
if (dcWidth < 1)
|
if (dcWidth < 1)
|
||||||
return;
|
return;
|
||||||
dc.SetFont(GetFontOk());
|
dc.SetFont(GetFontOk());
|
||||||
|
|
||||||
if (IsEnabled())
|
if (IsEnabled())
|
||||||
dc.SetTextForeground(GetForegroundColour());
|
dc.SetTextForeground(GetForegroundColour());
|
||||||
else
|
else
|
||||||
dc.SetTextForeground(*wxLIGHT_GREY);
|
dc.SetTextForeground(*wxLIGHT_GREY);
|
||||||
|
|
||||||
pxWindowTextWriter writer(dc);
|
pxWindowTextWriter writer(dc);
|
||||||
writer.Align(m_align);
|
writer.Align(m_align);
|
||||||
|
|
||||||
const wxString &label(m_autowrap ? m_wrappedLabel : m_label);
|
const wxString& label(m_autowrap ? m_wrappedLabel : m_label);
|
||||||
if (m_autowrap)
|
if (m_autowrap)
|
||||||
_updateWrapping(false);
|
_updateWrapping(false);
|
||||||
|
|
||||||
int tWidth, tHeight;
|
int tWidth, tHeight;
|
||||||
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
|
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
|
||||||
|
|
||||||
writer.Align(m_align);
|
writer.Align(m_align);
|
||||||
if (m_align & wxALIGN_CENTER_VERTICAL)
|
if (m_align & wxALIGN_CENTER_VERTICAL)
|
||||||
writer.SetY((dcHeight - tHeight) / 2);
|
writer.SetY((dcHeight - tHeight) / 2);
|
||||||
else
|
else
|
||||||
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
|
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
|
||||||
|
|
||||||
writer.WriteLn(label); // without formatting please.
|
writer.WriteLn(label); // without formatting please.
|
||||||
|
|
||||||
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
||||||
//dc.DrawRectangle(wxPoint(), dc.GetSize());
|
//dc.DrawRectangle(wxPoint(), dc.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded form wxPanel and friends.
|
// Overloaded form wxPanel and friends.
|
||||||
wxSize pxStaticText::DoGetBestSize() const
|
wxSize pxStaticText::DoGetBestSize() const
|
||||||
{
|
{
|
||||||
wxClientDC dc(const_cast<pxStaticText *>(this));
|
wxClientDC dc(const_cast<pxStaticText*>(this));
|
||||||
dc.SetFont(GetFontOk());
|
dc.SetFont(GetFontOk());
|
||||||
|
|
||||||
wxSize best;
|
wxSize best;
|
||||||
|
|
||||||
if (m_autowrap) {
|
if (m_autowrap)
|
||||||
best = GetBestWrappedSize(dc);
|
{
|
||||||
//best.x = wxDefaultCoord;
|
best = GetBestWrappedSize(dc);
|
||||||
} else {
|
//best.x = wxDefaultCoord;
|
||||||
// No autowrapping, so we can force a specific size here!
|
}
|
||||||
best = dc.GetMultiLineTextExtent(GetLabel());
|
else
|
||||||
best.x += calcPaddingWidth(best.x);
|
{
|
||||||
}
|
// No autowrapping, so we can force a specific size here!
|
||||||
|
best = dc.GetMultiLineTextExtent(GetLabel());
|
||||||
|
best.x += calcPaddingWidth(best.x);
|
||||||
|
}
|
||||||
|
|
||||||
best.y += calcPaddingHeight(best.y);
|
best.y += calcPaddingHeight(best.y);
|
||||||
|
|
||||||
CacheBestSize(best);
|
CacheBestSize(best);
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxStaticHeading (implementations)
|
// pxStaticHeading (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxStaticHeading::pxStaticHeading(wxWindow *parent, const wxString &label)
|
pxStaticHeading::pxStaticHeading(wxWindow* parent, const wxString& label)
|
||||||
: _parent(parent)
|
: _parent(parent)
|
||||||
{
|
{
|
||||||
m_align = wxALIGN_CENTER;
|
m_align = wxALIGN_CENTER;
|
||||||
|
|
||||||
SetPaddingDefaults();
|
SetPaddingDefaults();
|
||||||
Init(label);
|
Init(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxStaticHeading::SetPaddingDefaults()
|
void pxStaticHeading::SetPaddingDefaults()
|
||||||
{
|
{
|
||||||
m_paddingPix_horiz = 4;
|
m_paddingPix_horiz = 4;
|
||||||
m_paddingPix_vert = 1;
|
m_paddingPix_vert = 1;
|
||||||
|
|
||||||
m_paddingPct_horiz = 0.08f;
|
m_paddingPct_horiz = 0.08f;
|
||||||
m_paddingPct_vert = 0.0f;
|
m_paddingPct_vert = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, pxStaticText *src)
|
void operator+=(wxSizer& target, pxStaticText* src)
|
||||||
{
|
{
|
||||||
if (src)
|
if (src)
|
||||||
target.Add(src, pxExpand);
|
target.Add(src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, pxStaticText &src)
|
void operator+=(wxSizer& target, pxStaticText& src)
|
||||||
{
|
{
|
||||||
target.Add(&src, pxExpand);
|
target.Add(&src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer *target, pxStaticText &src)
|
void operator+=(wxSizer* target, pxStaticText& src)
|
||||||
{
|
{
|
||||||
target->Add(&src, pxExpand);
|
target->Add(&src, pxExpand);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,92 +34,92 @@
|
||||||
//
|
//
|
||||||
class pxStaticText : public wxControl
|
class pxStaticText : public wxControl
|
||||||
{
|
{
|
||||||
typedef wxControl _parent;
|
typedef wxControl _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_label;
|
wxString m_label;
|
||||||
wxString m_wrappedLabel;
|
wxString m_wrappedLabel;
|
||||||
|
|
||||||
wxAlignment m_align;
|
wxAlignment m_align;
|
||||||
bool m_autowrap;
|
bool m_autowrap;
|
||||||
int m_wrappedWidth;
|
int m_wrappedWidth;
|
||||||
int m_heightInLines;
|
int m_heightInLines;
|
||||||
|
|
||||||
int m_paddingPix_horiz;
|
int m_paddingPix_horiz;
|
||||||
int m_paddingPix_vert;
|
int m_paddingPix_vert;
|
||||||
float m_paddingPct_horiz;
|
float m_paddingPct_horiz;
|
||||||
float m_paddingPct_vert;
|
float m_paddingPct_vert;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit pxStaticText(wxWindow *parent = NULL);
|
explicit pxStaticText(wxWindow* parent = NULL);
|
||||||
|
|
||||||
// wxWindow overloads!
|
// wxWindow overloads!
|
||||||
bool AcceptsFocus() const { return false; }
|
bool AcceptsFocus() const { return false; }
|
||||||
bool HasTransparentBackground() { return true; }
|
bool HasTransparentBackground() { return true; }
|
||||||
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
|
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||||
pxStaticText(wxWindow *parent, int heightInLines, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
pxStaticText(wxWindow* parent, int heightInLines, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||||
virtual ~pxStaticText() = default;
|
virtual ~pxStaticText() = default;
|
||||||
|
|
||||||
wxFont GetFontOk() const;
|
wxFont GetFontOk() const;
|
||||||
bool Enable(bool enabled = true);
|
bool Enable(bool enabled = true);
|
||||||
|
|
||||||
virtual void SetLabel(const wxString &label);
|
virtual void SetLabel(const wxString& label);
|
||||||
virtual wxString GetLabel() const { return m_label; }
|
virtual wxString GetLabel() const { return m_label; }
|
||||||
|
|
||||||
pxStaticText &SetMinWidth(int width);
|
pxStaticText& SetMinWidth(int width);
|
||||||
pxStaticText &SetMinHeight(int height);
|
pxStaticText& SetMinHeight(int height);
|
||||||
|
|
||||||
pxStaticText &SetHeight(int lines);
|
pxStaticText& SetHeight(int lines);
|
||||||
pxStaticText &Align(wxAlignment align);
|
pxStaticText& Align(wxAlignment align);
|
||||||
pxStaticText &Bold();
|
pxStaticText& Bold();
|
||||||
pxStaticText &WrapAt(int width);
|
pxStaticText& WrapAt(int width);
|
||||||
|
|
||||||
pxStaticText &Unwrapped();
|
pxStaticText& Unwrapped();
|
||||||
|
|
||||||
pxStaticText &PaddingPixH(int pixels);
|
pxStaticText& PaddingPixH(int pixels);
|
||||||
pxStaticText &PaddingPixV(int pixels);
|
pxStaticText& PaddingPixV(int pixels);
|
||||||
|
|
||||||
pxStaticText &PaddingPctH(float pct);
|
pxStaticText& PaddingPctH(float pct);
|
||||||
pxStaticText &PaddingPctV(float pct);
|
pxStaticText& PaddingPctV(float pct);
|
||||||
//pxStaticText& DoBestGuessHeight();
|
//pxStaticText& DoBestGuessHeight();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetPaddingDefaults();
|
void SetPaddingDefaults();
|
||||||
void Init(const wxString &label);
|
void Init(const wxString& label);
|
||||||
|
|
||||||
wxSize GetBestWrappedSize(const wxClientDC &dc) const;
|
wxSize GetBestWrappedSize(const wxClientDC& dc) const;
|
||||||
wxSize DoGetBestSize() const;
|
wxSize DoGetBestSize() const;
|
||||||
|
|
||||||
int calcPaddingWidth(int newWidth) const;
|
int calcPaddingWidth(int newWidth) const;
|
||||||
int calcPaddingHeight(int newHeight) const;
|
int calcPaddingHeight(int newHeight) const;
|
||||||
|
|
||||||
void paintEvent(wxPaintEvent &evt);
|
void paintEvent(wxPaintEvent& evt);
|
||||||
|
|
||||||
void UpdateWrapping(bool textChanged);
|
void UpdateWrapping(bool textChanged);
|
||||||
bool _updateWrapping(bool textChanged);
|
bool _updateWrapping(bool textChanged);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class pxStaticHeading : public pxStaticText
|
class pxStaticHeading : public pxStaticText
|
||||||
{
|
{
|
||||||
typedef pxStaticText _parent;
|
typedef pxStaticText _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxStaticHeading(wxWindow *parent = NULL, const wxString &label = wxEmptyString);
|
pxStaticHeading(wxWindow* parent = NULL, const wxString& label = wxEmptyString);
|
||||||
pxStaticHeading(wxWindow *parent, int heightInLines, const wxString &label = wxEmptyString);
|
pxStaticHeading(wxWindow* parent, int heightInLines, const wxString& label = wxEmptyString);
|
||||||
virtual ~pxStaticHeading() = default;
|
virtual ~pxStaticHeading() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetPaddingDefaults();
|
void SetPaddingDefaults();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void operator+=(wxSizer &target, pxStaticText &src);
|
extern void operator+=(wxSizer& target, pxStaticText& src);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxStaticText> &src)
|
inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxStaticText>& src)
|
||||||
{
|
{
|
||||||
target.Add(src.window, src.flags);
|
target.Add(src.window, src.flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,22 +23,22 @@
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxStreamBase (implementations)
|
// pxStreamBase (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxStreamBase::pxStreamBase(const wxString &filename)
|
pxStreamBase::pxStreamBase(const wxString& filename)
|
||||||
: m_filename(filename)
|
: m_filename(filename)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxStreamBase::IsOk() const
|
bool pxStreamBase::IsOk() const
|
||||||
{
|
{
|
||||||
wxStreamBase *woot = GetWxStreamBase();
|
wxStreamBase* woot = GetWxStreamBase();
|
||||||
return woot && woot->IsOk();
|
return woot && woot->IsOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset pxStreamBase::Length() const
|
wxFileOffset pxStreamBase::Length() const
|
||||||
{
|
{
|
||||||
if (!GetWxStreamBase())
|
if (!GetWxStreamBase())
|
||||||
return 0;
|
return 0;
|
||||||
return GetWxStreamBase()->GetLength();
|
return GetWxStreamBase()->GetLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -47,115 +47,117 @@ wxFileOffset pxStreamBase::Length() const
|
||||||
// Interface for reading data from a gzip stream.
|
// Interface for reading data from a gzip stream.
|
||||||
//
|
//
|
||||||
|
|
||||||
pxInputStream::pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input)
|
pxInputStream::pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input)
|
||||||
: pxStreamBase(filename)
|
: pxStreamBase(filename)
|
||||||
, m_stream_in(std::move(input))
|
, m_stream_in(std::move(input))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pxInputStream::pxInputStream(const wxString &filename, wxInputStream *input)
|
pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input)
|
||||||
: pxStreamBase(filename)
|
: pxStreamBase(filename)
|
||||||
, m_stream_in(input)
|
, m_stream_in(input)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
wxStreamBase *pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); }
|
wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); }
|
||||||
|
|
||||||
wxFileOffset pxInputStream::Tell() const
|
wxFileOffset pxInputStream::Tell() const
|
||||||
{
|
{
|
||||||
return m_stream_in->TellI();
|
return m_stream_in->TellI();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset pxInputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
wxFileOffset pxInputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||||
{
|
{
|
||||||
return m_stream_in->SeekI(ofs, mode);
|
return m_stream_in->SeekI(ofs, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxInputStream::SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream)
|
void pxInputStream::SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream)
|
||||||
{
|
{
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_stream_in = std::move(stream);
|
m_stream_in = std::move(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxInputStream::SetStream(const wxString &filename, wxInputStream *stream)
|
void pxInputStream::SetStream(const wxString& filename, wxInputStream* stream)
|
||||||
{
|
{
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_stream_in = std::unique_ptr<wxInputStream>(stream);
|
m_stream_in = std::unique_ptr<wxInputStream>(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxInputStream::Read(void *dest, size_t size)
|
void pxInputStream::Read(void* dest, size_t size)
|
||||||
{
|
{
|
||||||
m_stream_in->Read(dest, size);
|
m_stream_in->Read(dest, size);
|
||||||
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR) {
|
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
|
||||||
int err = errno;
|
{
|
||||||
if (!err)
|
int err = errno;
|
||||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
if (!err)
|
||||||
|
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
||||||
|
|
||||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||||
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
|
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
|
||||||
ex->Rethrow();
|
ex->Rethrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we
|
// IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we
|
||||||
// must always use the explicit check against the number of bytes read to determine
|
// must always use the explicit check against the number of bytes read to determine
|
||||||
// end-of-stream conditions.
|
// end-of-stream conditions.
|
||||||
|
|
||||||
if ((size_t)m_stream_in->LastRead() < size)
|
if ((size_t)m_stream_in->LastRead() < size)
|
||||||
throw Exception::EndOfStream(m_filename);
|
throw Exception::EndOfStream(m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxOutputStream
|
// pxOutputStream
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxOutputStream::pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output)
|
pxOutputStream::pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output)
|
||||||
: pxStreamBase(filename)
|
: pxStreamBase(filename)
|
||||||
, m_stream_out(std::move(output))
|
, m_stream_out(std::move(output))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pxOutputStream::pxOutputStream(const wxString &filename, wxOutputStream *output)
|
pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output)
|
||||||
: pxStreamBase(filename)
|
: pxStreamBase(filename)
|
||||||
, m_stream_out(output)
|
, m_stream_out(output)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
wxStreamBase *pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); }
|
wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); }
|
||||||
|
|
||||||
wxFileOffset pxOutputStream::Tell() const
|
wxFileOffset pxOutputStream::Tell() const
|
||||||
{
|
{
|
||||||
return m_stream_out->TellO();
|
return m_stream_out->TellO();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset pxOutputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
wxFileOffset pxOutputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||||
{
|
{
|
||||||
return m_stream_out->SeekO(ofs, mode);
|
return m_stream_out->SeekO(ofs, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxOutputStream::SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream)
|
void pxOutputStream::SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream)
|
||||||
{
|
{
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_stream_out = std::move(stream);
|
m_stream_out = std::move(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxOutputStream::SetStream(const wxString &filename, wxOutputStream *stream)
|
void pxOutputStream::SetStream(const wxString& filename, wxOutputStream* stream)
|
||||||
{
|
{
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_stream_out = std::unique_ptr<wxOutputStream>(stream);
|
m_stream_out = std::unique_ptr<wxOutputStream>(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pxOutputStream::Write(const void *src, size_t size)
|
void pxOutputStream::Write(const void* src, size_t size)
|
||||||
{
|
{
|
||||||
m_stream_out->Write(src, size);
|
m_stream_out->Write(src, size);
|
||||||
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR) {
|
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
|
||||||
int err = errno;
|
{
|
||||||
if (!err)
|
int err = errno;
|
||||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
if (!err)
|
||||||
|
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
||||||
|
|
||||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||||
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
|
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
|
||||||
ex->Rethrow();
|
ex->Rethrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -163,89 +165,93 @@ void pxOutputStream::Write(const void *src, size_t size)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap.
|
// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap.
|
||||||
bool pxReadLine(wxInputStream &input, std::string &dest)
|
bool pxReadLine(wxInputStream& input, std::string& dest)
|
||||||
{
|
{
|
||||||
dest.clear();
|
dest.clear();
|
||||||
bool isUTF8 = false;
|
bool isUTF8 = false;
|
||||||
while (true) {
|
while (true)
|
||||||
char c;
|
{
|
||||||
input.Read(&c, sizeof(c));
|
char c;
|
||||||
if (c == 0)
|
input.Read(&c, sizeof(c));
|
||||||
break;
|
if (c == 0)
|
||||||
if (input.Eof())
|
break;
|
||||||
break;
|
if (input.Eof())
|
||||||
if (c == '\n')
|
break;
|
||||||
break; // eat on UNIX
|
if (c == '\n')
|
||||||
if (c == '\r') {
|
break; // eat on UNIX
|
||||||
input.Read(&c, sizeof(c));
|
if (c == '\r')
|
||||||
if (c == 0)
|
{
|
||||||
break;
|
input.Read(&c, sizeof(c));
|
||||||
if (input.Eof())
|
if (c == 0)
|
||||||
break;
|
break;
|
||||||
if (c == '\n')
|
if (input.Eof())
|
||||||
break;
|
break;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
input.Ungetch(c);
|
input.Ungetch(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dest += c;
|
dest += c;
|
||||||
if (c & 0x80)
|
if (c & 0x80)
|
||||||
isUTF8 = true;
|
isUTF8 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isUTF8;
|
return isUTF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed)
|
void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed)
|
||||||
{
|
{
|
||||||
dest.clear();
|
dest.clear();
|
||||||
if (pxReadLine(input, intermed))
|
if (pxReadLine(input, intermed))
|
||||||
dest = fromUTF8(intermed.c_str());
|
dest = fromUTF8(intermed.c_str());
|
||||||
else {
|
else
|
||||||
// Optimized ToAscii conversion.
|
{
|
||||||
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
// Optimized ToAscii conversion.
|
||||||
const char *ascii = intermed.c_str();
|
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
||||||
while (*ascii != 0)
|
const char* ascii = intermed.c_str();
|
||||||
dest += (wchar_t)(unsigned char)*ascii++;
|
while (*ascii != 0)
|
||||||
}
|
dest += (wchar_t)(unsigned char)*ascii++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxReadLine(wxInputStream &input, wxString &dest)
|
void pxReadLine(wxInputStream& input, wxString& dest)
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
pxReadLine(input, dest, line);
|
pxReadLine(input, dest, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString pxReadLine(wxInputStream &input)
|
wxString pxReadLine(wxInputStream& input)
|
||||||
{
|
{
|
||||||
wxString result;
|
wxString result;
|
||||||
pxReadLine(input, result);
|
pxReadLine(input, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxWriteLine(wxOutputStream &output)
|
void pxWriteLine(wxOutputStream& output)
|
||||||
{
|
{
|
||||||
output.Write("\n", 1);
|
output.Write("\n", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxWriteLine(wxOutputStream &output, const wxString &text)
|
void pxWriteLine(wxOutputStream& output, const wxString& text)
|
||||||
{
|
{
|
||||||
if (!text.IsEmpty()) {
|
if (!text.IsEmpty())
|
||||||
pxToUTF8 utf8(text);
|
{
|
||||||
output.Write(utf8, utf8.Length());
|
pxToUTF8 utf8(text);
|
||||||
}
|
output.Write(utf8, utf8.Length());
|
||||||
pxWriteLine(output);
|
}
|
||||||
|
pxWriteLine(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxWriteMultiline(wxOutputStream &output, const wxString &src)
|
void pxWriteMultiline(wxOutputStream& output, const wxString& src)
|
||||||
{
|
{
|
||||||
if (src.IsEmpty())
|
if (src.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxString result(src);
|
wxString result(src);
|
||||||
result.Replace(L"\r\n", L"\n");
|
result.Replace(L"\r\n", L"\n");
|
||||||
result.Replace(L"\r", L"\n");
|
result.Replace(L"\r", L"\n");
|
||||||
|
|
||||||
pxToUTF8 utf8(result);
|
pxToUTF8 utf8(result);
|
||||||
output.Write(utf8, utf8.Length());
|
output.Write(utf8, utf8.Length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,28 +25,28 @@
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxStreamBase
|
class pxStreamBase
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(pxStreamBase);
|
DeclareNoncopyableObject(pxStreamBase);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Filename of the stream, provided by the creator/caller. This is typically used *only*
|
// Filename of the stream, provided by the creator/caller. This is typically used *only*
|
||||||
// for generating comprehensive error messages when an error occurs (the stream name is
|
// for generating comprehensive error messages when an error occurs (the stream name is
|
||||||
// passed to the exception handlers).
|
// passed to the exception handlers).
|
||||||
wxString m_filename;
|
wxString m_filename;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxStreamBase(const wxString &filename);
|
pxStreamBase(const wxString& filename);
|
||||||
virtual ~pxStreamBase() = default;
|
virtual ~pxStreamBase() = default;
|
||||||
|
|
||||||
// Implementing classes should return the base wxStream object (usually either a wxInputStream
|
// Implementing classes should return the base wxStream object (usually either a wxInputStream
|
||||||
// or wxOputStream derivative).
|
// or wxOputStream derivative).
|
||||||
virtual wxStreamBase *GetWxStreamBase() const = 0;
|
virtual wxStreamBase* GetWxStreamBase() const = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
virtual wxFileOffset Tell() const = 0;
|
virtual wxFileOffset Tell() const = 0;
|
||||||
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
|
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
|
||||||
|
|
||||||
virtual wxFileOffset Length() const;
|
virtual wxFileOffset Length() const;
|
||||||
bool IsOk() const;
|
bool IsOk() const;
|
||||||
wxString GetStreamName() const { return m_filename; }
|
wxString GetStreamName() const { return m_filename; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,33 +55,33 @@ public:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxOutputStream : public pxStreamBase
|
class pxOutputStream : public pxStreamBase
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(pxOutputStream);
|
DeclareNoncopyableObject(pxOutputStream);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<wxOutputStream> m_stream_out;
|
std::unique_ptr<wxOutputStream> m_stream_out;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output);
|
pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output);
|
||||||
pxOutputStream(const wxString &filename, wxOutputStream *output);
|
pxOutputStream(const wxString& filename, wxOutputStream* output);
|
||||||
|
|
||||||
virtual ~pxOutputStream() = default;
|
virtual ~pxOutputStream() = default;
|
||||||
virtual void Write(const void *data, size_t size);
|
virtual void Write(const void* data, size_t size);
|
||||||
|
|
||||||
void SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream);
|
void SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream);
|
||||||
void SetStream(const wxString &filename, wxOutputStream *stream);
|
void SetStream(const wxString& filename, wxOutputStream* stream);
|
||||||
|
|
||||||
void Close() { m_stream_out = nullptr; }
|
void Close() { m_stream_out = nullptr; }
|
||||||
|
|
||||||
virtual wxStreamBase *GetWxStreamBase() const;
|
virtual wxStreamBase* GetWxStreamBase() const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(const T &data)
|
void Write(const T& data)
|
||||||
{
|
{
|
||||||
Write(&data, sizeof(data));
|
Write(&data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset Tell() const;
|
wxFileOffset Tell() const;
|
||||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -89,31 +89,31 @@ public:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxInputStream : public pxStreamBase
|
class pxInputStream : public pxStreamBase
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(pxInputStream);
|
DeclareNoncopyableObject(pxInputStream);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<wxInputStream> m_stream_in;
|
std::unique_ptr<wxInputStream> m_stream_in;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input);
|
pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input);
|
||||||
pxInputStream(const wxString &filename, wxInputStream *input);
|
pxInputStream(const wxString& filename, wxInputStream* input);
|
||||||
|
|
||||||
virtual ~pxInputStream() = default;
|
virtual ~pxInputStream() = default;
|
||||||
virtual void Read(void *dest, size_t size);
|
virtual void Read(void* dest, size_t size);
|
||||||
|
|
||||||
void SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream);
|
void SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream);
|
||||||
void SetStream(const wxString &filename, wxInputStream *stream);
|
void SetStream(const wxString& filename, wxInputStream* stream);
|
||||||
|
|
||||||
void Close() { m_stream_in = nullptr; }
|
void Close() { m_stream_in = nullptr; }
|
||||||
|
|
||||||
virtual wxStreamBase *GetWxStreamBase() const;
|
virtual wxStreamBase* GetWxStreamBase() const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Read(T &dest)
|
void Read(T& dest)
|
||||||
{
|
{
|
||||||
Read(&dest, sizeof(dest));
|
Read(&dest, sizeof(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset Tell() const;
|
wxFileOffset Tell() const;
|
||||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,12 +25,12 @@ bool pxIsEnglish(int id)
|
||||||
// pxExpandMsg -- an Iconized Text Translator
|
// pxExpandMsg -- an Iconized Text Translator
|
||||||
// Was replaced by a standard implementation of wxGetTranslation
|
// Was replaced by a standard implementation of wxGetTranslation
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
const wxChar *__fastcall pxExpandMsg(const wxChar *message)
|
const wxChar* __fastcall pxExpandMsg(const wxChar* message)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(message).wc_str();
|
return wxGetTranslation(message).wc_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxChar *__fastcall pxGetTranslation(const wxChar *message)
|
const wxChar* __fastcall pxGetTranslation(const wxChar* message)
|
||||||
{
|
{
|
||||||
return wxGetTranslation(message).wc_str();
|
return wxGetTranslation(message).wc_str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,137 +20,140 @@
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxWindowTextWriter Implementations
|
// pxWindowTextWriter Implementations
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxWindowTextWriter::pxWindowTextWriter(wxDC &dc)
|
pxWindowTextWriter::pxWindowTextWriter(wxDC& dc)
|
||||||
: m_dc(dc)
|
: m_dc(dc)
|
||||||
{
|
{
|
||||||
m_curpos = wxPoint();
|
m_curpos = wxPoint();
|
||||||
m_align = wxALIGN_CENTER;
|
m_align = wxALIGN_CENTER;
|
||||||
m_leading = 0;
|
m_leading = 0;
|
||||||
|
|
||||||
OnFontChanged();
|
OnFontChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxWindowTextWriter::OnFontChanged()
|
void pxWindowTextWriter::OnFontChanged()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::SetWeight(wxFontWeight weight)
|
pxWindowTextWriter& pxWindowTextWriter::SetWeight(wxFontWeight weight)
|
||||||
{
|
{
|
||||||
wxFont curfont(m_dc.GetFont());
|
wxFont curfont(m_dc.GetFont());
|
||||||
curfont.SetWeight(weight);
|
curfont.SetWeight(weight);
|
||||||
m_dc.SetFont(curfont);
|
m_dc.SetFont(curfont);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::SetStyle(wxFontStyle style)
|
pxWindowTextWriter& pxWindowTextWriter::SetStyle(wxFontStyle style)
|
||||||
{
|
{
|
||||||
wxFont curfont(m_dc.GetFont());
|
wxFont curfont(m_dc.GetFont());
|
||||||
curfont.SetStyle(style);
|
curfont.SetStyle(style);
|
||||||
m_dc.SetFont(curfont);
|
m_dc.SetFont(curfont);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::Normal()
|
pxWindowTextWriter& pxWindowTextWriter::Normal()
|
||||||
{
|
{
|
||||||
wxFont curfont(m_dc.GetFont());
|
wxFont curfont(m_dc.GetFont());
|
||||||
curfont.SetStyle(wxFONTSTYLE_NORMAL);
|
curfont.SetStyle(wxFONTSTYLE_NORMAL);
|
||||||
curfont.SetWeight(wxFONTWEIGHT_NORMAL);
|
curfont.SetWeight(wxFONTWEIGHT_NORMAL);
|
||||||
m_dc.SetFont(curfont);
|
m_dc.SetFont(curfont);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::SetPos(const wxPoint &pos)
|
pxWindowTextWriter& pxWindowTextWriter::SetPos(const wxPoint& pos)
|
||||||
{
|
{
|
||||||
m_curpos = pos;
|
m_curpos = pos;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::MovePos(const wxSize &delta)
|
pxWindowTextWriter& pxWindowTextWriter::MovePos(const wxSize& delta)
|
||||||
{
|
{
|
||||||
m_curpos += delta;
|
m_curpos += delta;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::SetY(int ypos)
|
pxWindowTextWriter& pxWindowTextWriter::SetY(int ypos)
|
||||||
{
|
{
|
||||||
m_curpos.y = ypos;
|
m_curpos.y = ypos;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::MoveY(int ydelta)
|
pxWindowTextWriter& pxWindowTextWriter::MoveY(int ydelta)
|
||||||
{
|
{
|
||||||
m_curpos.y += ydelta;
|
m_curpos.y += ydelta;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxWindowTextWriter::_DoWriteLn(const wxString &msg)
|
void pxWindowTextWriter::_DoWriteLn(const wxString& msg)
|
||||||
{
|
{
|
||||||
int tWidth, tHeight;
|
int tWidth, tHeight;
|
||||||
m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight);
|
m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight);
|
||||||
|
|
||||||
wxPoint dispos(m_curpos);
|
wxPoint dispos(m_curpos);
|
||||||
|
|
||||||
if (m_align & wxALIGN_CENTER_HORIZONTAL) {
|
if (m_align & wxALIGN_CENTER_HORIZONTAL)
|
||||||
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
{
|
||||||
} else if (m_align & wxALIGN_RIGHT) {
|
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
||||||
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
}
|
||||||
}
|
else if (m_align & wxALIGN_RIGHT)
|
||||||
|
{
|
||||||
|
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
||||||
|
}
|
||||||
|
|
||||||
m_dc.DrawText(msg, dispos);
|
m_dc.DrawText(msg, dispos);
|
||||||
m_curpos.y += tHeight + m_leading;
|
m_curpos.y += tHeight + m_leading;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits incoming multi-line strings into pieces, and dispatches each line individually
|
// Splits incoming multi-line strings into pieces, and dispatches each line individually
|
||||||
// to the text writer.
|
// to the text writer.
|
||||||
void pxWindowTextWriter::_DoWrite(const wxChar *msg)
|
void pxWindowTextWriter::_DoWrite(const wxChar* msg)
|
||||||
{
|
{
|
||||||
pxAssert(msg);
|
pxAssert(msg);
|
||||||
|
|
||||||
wxArrayString parts;
|
wxArrayString parts;
|
||||||
SplitString(parts, msg, L'\n');
|
SplitString(parts, msg, L'\n');
|
||||||
|
|
||||||
for (size_t i = 0; i < parts.GetCount(); ++i)
|
for (size_t i = 0; i < parts.GetCount(); ++i)
|
||||||
_DoWriteLn(parts[i]);
|
_DoWriteLn(parts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::SetFont(const wxFont &font)
|
pxWindowTextWriter& pxWindowTextWriter::SetFont(const wxFont& font)
|
||||||
{
|
{
|
||||||
m_dc.SetFont(font);
|
m_dc.SetFont(font);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::Align(const wxAlignment &align)
|
pxWindowTextWriter& pxWindowTextWriter::Align(const wxAlignment& align)
|
||||||
{
|
{
|
||||||
m_align = align;
|
m_align = align;
|
||||||
m_curpos.x = 0;
|
m_curpos.x = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn()
|
pxWindowTextWriter& pxWindowTextWriter::WriteLn()
|
||||||
{
|
{
|
||||||
_DoWriteLn(L"");
|
_DoWriteLn(L"");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxChar *fmt)
|
pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxChar* fmt)
|
||||||
{
|
{
|
||||||
_DoWrite(fmt);
|
_DoWrite(fmt);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::FormatLn(const wxChar *fmt, ...)
|
pxWindowTextWriter& pxWindowTextWriter::FormatLn(const wxChar* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
_DoWrite(pxsFmtV(fmt, args));
|
_DoWrite(pxsFmtV(fmt, args));
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxString fmt)
|
pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxString fmt)
|
||||||
{
|
{
|
||||||
_DoWrite(fmt.wc_str());
|
_DoWrite(fmt.wc_str());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,21 +27,21 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxSimpleEvent, wxEvent);
|
||||||
|
|
||||||
ConsoleLogSource_App::ConsoleLogSource_App()
|
ConsoleLogSource_App::ConsoleLogSource_App()
|
||||||
{
|
{
|
||||||
static const TraceLogDescriptor myDesc =
|
static const TraceLogDescriptor myDesc =
|
||||||
{
|
{
|
||||||
L"AppEvents", L"App Events",
|
L"AppEvents", L"App Events",
|
||||||
pxLt("Includes idle event processing and some other uncommon event usages.")};
|
pxLt("Includes idle event processing and some other uncommon event usages.")};
|
||||||
|
|
||||||
m_Descriptor = &myDesc;
|
m_Descriptor = &myDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleLogSource_App pxConLog_App;
|
ConsoleLogSource_App pxConLog_App;
|
||||||
|
|
||||||
void BaseDeletableObject::DoDeletion()
|
void BaseDeletableObject::DoDeletion()
|
||||||
{
|
{
|
||||||
wxAppWithHelpers *app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
|
wxAppWithHelpers* app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
|
||||||
pxAssert(app != NULL);
|
pxAssert(app != NULL);
|
||||||
app->DeleteObject(*this);
|
app->DeleteObject(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,64 +49,67 @@ void BaseDeletableObject::DoDeletion()
|
||||||
// SynchronousActionState Implementations
|
// SynchronousActionState Implementations
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void SynchronousActionState::SetException(const BaseException &ex)
|
void SynchronousActionState::SetException(const BaseException& ex)
|
||||||
{
|
{
|
||||||
m_exception = ScopedExcept(ex.Clone());
|
m_exception = ScopedExcept(ex.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousActionState::SetException(BaseException *ex)
|
void SynchronousActionState::SetException(BaseException* ex)
|
||||||
{
|
{
|
||||||
if (!m_posted) {
|
if (!m_posted)
|
||||||
m_exception = ScopedExcept(ex);
|
{
|
||||||
} else if (wxTheApp) {
|
m_exception = ScopedExcept(ex);
|
||||||
// transport the exception to the main thread, since the message is fully
|
}
|
||||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
else if (wxTheApp)
|
||||||
// as a non-blocking action since proper handling of user errors on async messages
|
{
|
||||||
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
// transport the exception to the main thread, since the message is fully
|
||||||
// box to the user.
|
// asynchronous, or has already entered an asynchronous state. Message is sent
|
||||||
|
// as a non-blocking action since proper handling of user errors on async messages
|
||||||
|
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
||||||
|
// box to the user.
|
||||||
|
|
||||||
pxExceptionEvent ev(ex);
|
pxExceptionEvent ev(ex);
|
||||||
wxTheApp->AddPendingEvent(ev);
|
wxTheApp->AddPendingEvent(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousActionState::RethrowException() const
|
void SynchronousActionState::RethrowException() const
|
||||||
{
|
{
|
||||||
if (m_exception)
|
if (m_exception)
|
||||||
m_exception->Rethrow();
|
m_exception->Rethrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SynchronousActionState::WaitForResult()
|
int SynchronousActionState::WaitForResult()
|
||||||
{
|
{
|
||||||
m_sema.WaitNoCancel();
|
m_sema.WaitNoCancel();
|
||||||
RethrowException();
|
RethrowException();
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SynchronousActionState::WaitForResult_NoExceptions()
|
int SynchronousActionState::WaitForResult_NoExceptions()
|
||||||
{
|
{
|
||||||
m_sema.WaitNoCancel();
|
m_sema.WaitNoCancel();
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousActionState::PostResult(int res)
|
void SynchronousActionState::PostResult(int res)
|
||||||
{
|
{
|
||||||
return_value = res;
|
return_value = res;
|
||||||
PostResult();
|
PostResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousActionState::ClearResult()
|
void SynchronousActionState::ClearResult()
|
||||||
{
|
{
|
||||||
m_posted = false;
|
m_posted = false;
|
||||||
m_exception = NULL;
|
m_exception = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousActionState::PostResult()
|
void SynchronousActionState::PostResult()
|
||||||
{
|
{
|
||||||
if (m_posted)
|
if (m_posted)
|
||||||
return;
|
return;
|
||||||
m_posted = true;
|
m_posted = true;
|
||||||
m_sema.Post();
|
m_sema.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -115,40 +118,41 @@ void SynchronousActionState::PostResult()
|
||||||
|
|
||||||
wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent);
|
wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent);
|
||||||
|
|
||||||
pxActionEvent::pxActionEvent(SynchronousActionState *sema, int msgtype)
|
pxActionEvent::pxActionEvent(SynchronousActionState* sema, int msgtype)
|
||||||
: wxEvent(0, msgtype)
|
: wxEvent(0, msgtype)
|
||||||
{
|
{
|
||||||
m_state = sema;
|
m_state = sema;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxActionEvent::pxActionEvent(SynchronousActionState &sema, int msgtype)
|
pxActionEvent::pxActionEvent(SynchronousActionState& sema, int msgtype)
|
||||||
: wxEvent(0, msgtype)
|
: wxEvent(0, msgtype)
|
||||||
{
|
{
|
||||||
m_state = &sema;
|
m_state = &sema;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxActionEvent::pxActionEvent(const pxActionEvent &src)
|
pxActionEvent::pxActionEvent(const pxActionEvent& src)
|
||||||
: wxEvent(src)
|
: wxEvent(src)
|
||||||
{
|
{
|
||||||
m_state = src.m_state;
|
m_state = src.m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxActionEvent::SetException(const BaseException &ex)
|
void pxActionEvent::SetException(const BaseException& ex)
|
||||||
{
|
{
|
||||||
SetException(ex.Clone());
|
SetException(ex.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxActionEvent::SetException(BaseException *ex)
|
void pxActionEvent::SetException(BaseException* ex)
|
||||||
{
|
{
|
||||||
const wxString &prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
||||||
ex->DiagMsg() = prefix + ex->DiagMsg();
|
ex->DiagMsg() = prefix + ex->DiagMsg();
|
||||||
|
|
||||||
if (!m_state) {
|
if (!m_state)
|
||||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
{
|
||||||
ex->Rethrow();
|
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||||
}
|
ex->Rethrow();
|
||||||
|
}
|
||||||
|
|
||||||
m_state->SetException(ex);
|
m_state->SetException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -156,58 +160,59 @@ void pxActionEvent::SetException(BaseException *ex)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
wxIMPLEMENT_DYNAMIC_CLASS(pxSynchronousCommandEvent, wxCommandEvent);
|
wxIMPLEMENT_DYNAMIC_CLASS(pxSynchronousCommandEvent, wxCommandEvent);
|
||||||
|
|
||||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, wxEventType commandType, int winid)
|
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, wxEventType commandType, int winid)
|
||||||
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
|
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
|
||||||
{
|
{
|
||||||
m_sync = sema;
|
m_sync = sema;
|
||||||
m_realEvent = commandType;
|
m_realEvent = commandType;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType, int winid)
|
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType, int winid)
|
||||||
: wxCommandEvent(pxEvt_SynchronousCommand)
|
: wxCommandEvent(pxEvt_SynchronousCommand)
|
||||||
{
|
{
|
||||||
m_sync = &sema;
|
m_sync = &sema;
|
||||||
m_realEvent = commandType;
|
m_realEvent = commandType;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt)
|
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt)
|
||||||
: wxCommandEvent(evt)
|
: wxCommandEvent(evt)
|
||||||
{
|
{
|
||||||
m_sync = sema;
|
m_sync = sema;
|
||||||
m_realEvent = evt.GetEventType();
|
m_realEvent = evt.GetEventType();
|
||||||
SetEventType(pxEvt_SynchronousCommand);
|
SetEventType(pxEvt_SynchronousCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt)
|
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt)
|
||||||
: wxCommandEvent(evt)
|
: wxCommandEvent(evt)
|
||||||
{
|
{
|
||||||
m_sync = &sema;
|
m_sync = &sema;
|
||||||
m_realEvent = evt.GetEventType();
|
m_realEvent = evt.GetEventType();
|
||||||
SetEventType(pxEvt_SynchronousCommand);
|
SetEventType(pxEvt_SynchronousCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src)
|
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src)
|
||||||
: wxCommandEvent(src)
|
: wxCommandEvent(src)
|
||||||
{
|
{
|
||||||
m_sync = src.m_sync;
|
m_sync = src.m_sync;
|
||||||
m_realEvent = src.m_realEvent;
|
m_realEvent = src.m_realEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxSynchronousCommandEvent::SetException(const BaseException &ex)
|
void pxSynchronousCommandEvent::SetException(const BaseException& ex)
|
||||||
{
|
{
|
||||||
if (!m_sync)
|
if (!m_sync)
|
||||||
ex.Rethrow();
|
ex.Rethrow();
|
||||||
m_sync->SetException(ex);
|
m_sync->SetException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxSynchronousCommandEvent::SetException(BaseException *ex)
|
void pxSynchronousCommandEvent::SetException(BaseException* ex)
|
||||||
{
|
{
|
||||||
if (!m_sync) {
|
if (!m_sync)
|
||||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
{
|
||||||
ex->Rethrow();
|
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||||
}
|
ex->Rethrow();
|
||||||
|
}
|
||||||
|
|
||||||
m_sync->SetException(ex);
|
m_sync->SetException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -219,46 +224,46 @@ void pxSynchronousCommandEvent::SetException(BaseException *ex)
|
||||||
//
|
//
|
||||||
class pxRpcEvent : public pxActionEvent
|
class pxRpcEvent : public pxActionEvent
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
|
||||||
|
|
||||||
typedef pxActionEvent _parent;
|
typedef pxActionEvent _parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void (*m_Method)();
|
void (*m_Method)();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~pxRpcEvent() = default;
|
virtual ~pxRpcEvent() = default;
|
||||||
virtual pxRpcEvent *Clone() const { return new pxRpcEvent(*this); }
|
virtual pxRpcEvent* Clone() const { return new pxRpcEvent(*this); }
|
||||||
|
|
||||||
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState *sema = NULL)
|
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState* sema = NULL)
|
||||||
: pxActionEvent(sema)
|
: pxActionEvent(sema)
|
||||||
{
|
{
|
||||||
m_Method = method;
|
m_Method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit pxRpcEvent(void (*method)(), SynchronousActionState &sema)
|
explicit pxRpcEvent(void (*method)(), SynchronousActionState& sema)
|
||||||
: pxActionEvent(sema)
|
: pxActionEvent(sema)
|
||||||
{
|
{
|
||||||
m_Method = method;
|
m_Method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRpcEvent(const pxRpcEvent &src)
|
pxRpcEvent(const pxRpcEvent& src)
|
||||||
: pxActionEvent(src)
|
: pxActionEvent(src)
|
||||||
{
|
{
|
||||||
m_Method = src.m_Method;
|
m_Method = src.m_Method;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMethod(void (*method)())
|
void SetMethod(void (*method)())
|
||||||
{
|
{
|
||||||
m_Method = method;
|
m_Method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InvokeEvent()
|
void InvokeEvent()
|
||||||
{
|
{
|
||||||
if (m_Method)
|
if (m_Method)
|
||||||
m_Method();
|
m_Method();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
|
wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
|
||||||
|
@ -266,16 +271,16 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxExceptionEvent implementations
|
// pxExceptionEvent implementations
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
pxExceptionEvent::pxExceptionEvent(const BaseException &ex)
|
pxExceptionEvent::pxExceptionEvent(const BaseException& ex)
|
||||||
{
|
{
|
||||||
m_except = ex.Clone();
|
m_except = ex.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxExceptionEvent::InvokeEvent()
|
void pxExceptionEvent::InvokeEvent()
|
||||||
{
|
{
|
||||||
ScopedExcept deleteMe(m_except);
|
ScopedExcept deleteMe(m_except);
|
||||||
if (deleteMe)
|
if (deleteMe)
|
||||||
deleteMe->Rethrow();
|
deleteMe->Rethrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -291,17 +296,17 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxAppWithHelpers, wxApp);
|
||||||
|
|
||||||
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
||||||
// main thread.
|
// main thread.
|
||||||
void wxAppWithHelpers::PostMethod(FnType_Void *method)
|
void wxAppWithHelpers::PostMethod(FnType_Void* method)
|
||||||
{
|
{
|
||||||
PostEvent(pxRpcEvent(method));
|
PostEvent(pxRpcEvent(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
||||||
// main thread.
|
// main thread.
|
||||||
void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
|
void wxAppWithHelpers::PostIdleMethod(FnType_Void* method)
|
||||||
{
|
{
|
||||||
pxRpcEvent evt(method);
|
pxRpcEvent evt(method);
|
||||||
AddIdleEvent(evt);
|
AddIdleEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invokes the specified void method, or posts the method to the main thread if the calling
|
// Invokes the specified void method, or posts the method to the main thread if the calling
|
||||||
|
@ -316,16 +321,16 @@ void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
|
||||||
// TRUE if the method was invoked.
|
// TRUE if the method was invoked.
|
||||||
//
|
//
|
||||||
|
|
||||||
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
|
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void* method)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain())
|
if (wxThread::IsMain())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
PostEvent(pxRpcEvent(method, sync));
|
PostEvent(pxRpcEvent(method, sync));
|
||||||
sync.WaitForResult();
|
sync.WaitForResult();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invokes the specified void method, or posts the method to the main thread if the calling
|
// Invokes the specified void method, or posts the method to the main thread if the calling
|
||||||
|
@ -339,93 +344,98 @@ bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
|
||||||
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
|
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
|
||||||
// TRUE if the method was posted.
|
// TRUE if the method was posted.
|
||||||
//
|
//
|
||||||
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void *method)
|
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void* method)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain())
|
if (wxThread::IsMain())
|
||||||
return false;
|
return false;
|
||||||
PostEvent(pxRpcEvent(method));
|
PostEvent(pxRpcEvent(method));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::ProcessMethod(FnType_Void *method)
|
void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain()) {
|
if (wxThread::IsMain())
|
||||||
method();
|
{
|
||||||
return;
|
method();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
PostEvent(pxRpcEvent(method, sync));
|
PostEvent(pxRpcEvent(method, sync));
|
||||||
sync.WaitForResult();
|
sync.WaitForResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::PostEvent(const wxEvent &evt)
|
void wxAppWithHelpers::PostEvent(const wxEvent& evt)
|
||||||
{
|
{
|
||||||
// Const Cast is OK!
|
// Const Cast is OK!
|
||||||
// Truth is, AddPendingEvent should be a const-qualified parameter, as
|
// Truth is, AddPendingEvent should be a const-qualified parameter, as
|
||||||
// it makes an immediate clone copy of the event -- but wxWidgets
|
// it makes an immediate clone copy of the event -- but wxWidgets
|
||||||
// fails again in structured C/C++ design design. So I'm forcing it as such
|
// fails again in structured C/C++ design design. So I'm forcing it as such
|
||||||
// here. -- air
|
// here. -- air
|
||||||
|
|
||||||
_parent::AddPendingEvent(const_cast<wxEvent &>(evt));
|
_parent::AddPendingEvent(const_cast<wxEvent&>(evt));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppWithHelpers::ProcessEvent(wxEvent &evt)
|
bool wxAppWithHelpers::ProcessEvent(wxEvent& evt)
|
||||||
{
|
{
|
||||||
// Note: We can't do an automatic blocking post of the message here, because wxWidgets
|
// Note: We can't do an automatic blocking post of the message here, because wxWidgets
|
||||||
// isn't really designed for it (some events return data to the caller via the event
|
// isn't really designed for it (some events return data to the caller via the event
|
||||||
// struct, and posting the event would require a temporary clone, where changes would
|
// struct, and posting the event would require a temporary clone, where changes would
|
||||||
// be lost).
|
// be lost).
|
||||||
|
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
return _parent::ProcessEvent(evt);
|
return _parent::ProcessEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppWithHelpers::ProcessEvent(wxEvent *evt)
|
bool wxAppWithHelpers::ProcessEvent(wxEvent* evt)
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||||
return _parent::ProcessEvent(*deleteMe);
|
return _parent::ProcessEvent(*deleteMe);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt)
|
bool wxAppWithHelpers::ProcessEvent(pxActionEvent& evt)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain())
|
if (wxThread::IsMain())
|
||||||
return _parent::ProcessEvent(evt);
|
return _parent::ProcessEvent(evt);
|
||||||
else {
|
else
|
||||||
SynchronousActionState sync;
|
{
|
||||||
evt.SetSyncState(sync);
|
SynchronousActionState sync;
|
||||||
AddPendingEvent(evt);
|
evt.SetSyncState(sync);
|
||||||
sync.WaitForResult();
|
AddPendingEvent(evt);
|
||||||
return true;
|
sync.WaitForResult();
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent *evt)
|
bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain()) {
|
if (wxThread::IsMain())
|
||||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
{
|
||||||
return _parent::ProcessEvent(*deleteMe);
|
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||||
} else {
|
return _parent::ProcessEvent(*deleteMe);
|
||||||
SynchronousActionState sync;
|
}
|
||||||
evt->SetSyncState(sync);
|
else
|
||||||
AddPendingEvent(*evt);
|
{
|
||||||
sync.WaitForResult();
|
SynchronousActionState sync;
|
||||||
return true;
|
evt->SetSyncState(sync);
|
||||||
}
|
AddPendingEvent(*evt);
|
||||||
|
sync.WaitForResult();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void wxAppWithHelpers::CleanUp()
|
void wxAppWithHelpers::CleanUp()
|
||||||
{
|
{
|
||||||
// I'm pretty sure the message pump is dead by now, which means we need to run through
|
// I'm pretty sure the message pump is dead by now, which means we need to run through
|
||||||
// idle event list by hand and process the pending Deletion messages (all others can be
|
// idle event list by hand and process the pending Deletion messages (all others can be
|
||||||
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
|
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
|
||||||
// but I like to be tidy. -- air
|
// but I like to be tidy. -- air
|
||||||
|
|
||||||
//IdleEventDispatcher( "CleanUp" );
|
//IdleEventDispatcher( "CleanUp" );
|
||||||
//DeletionDispatcher();
|
//DeletionDispatcher();
|
||||||
_parent::CleanUp();
|
_parent::CleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes the event with exception handling. If the event throws an exception, the exception
|
// Executes the event with exception handling. If the event throws an exception, the exception
|
||||||
|
@ -434,211 +444,227 @@ void wxAppWithHelpers::CleanUp()
|
||||||
// should overload InvokeEvent() instead.
|
// should overload InvokeEvent() instead.
|
||||||
void pxActionEvent::_DoInvokeEvent()
|
void pxActionEvent::_DoInvokeEvent()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
|
|
||||||
try {
|
try
|
||||||
InvokeEvent();
|
{
|
||||||
} catch (BaseException &ex) {
|
InvokeEvent();
|
||||||
SetException(ex);
|
}
|
||||||
} catch (std::runtime_error &ex) {
|
catch (BaseException& ex)
|
||||||
SetException(new Exception::RuntimeError(ex));
|
{
|
||||||
}
|
SetException(ex);
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
|
SetException(new Exception::RuntimeError(ex));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_state)
|
if (m_state)
|
||||||
m_state->PostResult();
|
m_state->PostResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent &evt)
|
void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent& evt)
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
|
|
||||||
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
||||||
evt.SetEventType(evt.GetRealEventType());
|
evt.SetEventType(evt.GetRealEventType());
|
||||||
|
|
||||||
try {
|
try
|
||||||
ProcessEvent(evt);
|
{
|
||||||
} catch (BaseException &ex) {
|
ProcessEvent(evt);
|
||||||
evt.SetException(ex);
|
}
|
||||||
} catch (std::runtime_error &ex) {
|
catch (BaseException& ex)
|
||||||
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
{
|
||||||
}
|
evt.SetException(ex);
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
|
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
||||||
|
}
|
||||||
|
|
||||||
if (Semaphore *sema = evt.GetSemaphore())
|
if (Semaphore* sema = evt.GetSemaphore())
|
||||||
sema->Post();
|
sema->Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::AddIdleEvent(const wxEvent &evt)
|
void wxAppWithHelpers::AddIdleEvent(const wxEvent& evt)
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_IdleEventMutex);
|
ScopedLock lock(m_IdleEventMutex);
|
||||||
if (m_IdleEventQueue.empty())
|
if (m_IdleEventQueue.empty())
|
||||||
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
|
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
|
||||||
|
|
||||||
m_IdleEventQueue.push_back(evt.Clone());
|
m_IdleEventQueue.push_back(evt.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent &evt)
|
void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
ScopedLock lock(m_IdleEventMutex);
|
ScopedLock lock(m_IdleEventMutex);
|
||||||
if (!m_IdleEventQueue.empty())
|
if (!m_IdleEventQueue.empty())
|
||||||
m_IdleEventTimer.Start(100, true);
|
m_IdleEventTimer.Start(100, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::IdleEventDispatcher(const wxChar *action)
|
void wxAppWithHelpers::IdleEventDispatcher(const wxChar* action)
|
||||||
{
|
{
|
||||||
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
|
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
|
||||||
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
|
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
|
||||||
// on each pass)
|
// on each pass)
|
||||||
|
|
||||||
//static int __guard=0;
|
//static int __guard=0;
|
||||||
//RecursionGuard guard(__guard);
|
//RecursionGuard guard(__guard);
|
||||||
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
|
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
|
||||||
|
|
||||||
wxEventList postponed;
|
wxEventList postponed;
|
||||||
wxEventList::iterator node;
|
wxEventList::iterator node;
|
||||||
|
|
||||||
ScopedLock lock(m_IdleEventMutex);
|
ScopedLock lock(m_IdleEventMutex);
|
||||||
|
|
||||||
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end()) {
|
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end())
|
||||||
std::unique_ptr<wxEvent> deleteMe(*node);
|
{
|
||||||
m_IdleEventQueue.erase(node);
|
std::unique_ptr<wxEvent> deleteMe(*node);
|
||||||
|
m_IdleEventQueue.erase(node);
|
||||||
|
|
||||||
lock.Release();
|
lock.Release();
|
||||||
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread)) {
|
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread))
|
||||||
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
|
{
|
||||||
// be deleted because those mutex/sema objects will become invalid and cause the pending
|
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
|
||||||
// thread to crash. So we disallow deletions when those waits are in action, and continue
|
// be deleted because those mutex/sema objects will become invalid and cause the pending
|
||||||
// to postpone the deletion of the thread until such time that it is safe.
|
// thread to crash. So we disallow deletions when those waits are in action, and continue
|
||||||
|
// to postpone the deletion of the thread until such time that it is safe.
|
||||||
|
|
||||||
pxThreadLog.Write(((pxThread *)((wxCommandEvent *)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
||||||
postponed.push_back(deleteMe.release());
|
postponed.push_back(deleteMe.release());
|
||||||
} else {
|
}
|
||||||
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
else
|
||||||
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
{
|
||||||
}
|
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
||||||
lock.Acquire();
|
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
||||||
}
|
}
|
||||||
|
lock.Acquire();
|
||||||
|
}
|
||||||
|
|
||||||
m_IdleEventQueue = postponed;
|
m_IdleEventQueue = postponed;
|
||||||
if (!m_IdleEventQueue.empty())
|
if (!m_IdleEventQueue.empty())
|
||||||
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
|
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnIdleEvent(wxIdleEvent &evt)
|
void wxAppWithHelpers::OnIdleEvent(wxIdleEvent& evt)
|
||||||
{
|
{
|
||||||
m_IdleEventTimer.Stop();
|
m_IdleEventTimer.Stop();
|
||||||
IdleEventDispatcher();
|
IdleEventDispatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent &evt)
|
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent& evt)
|
||||||
{
|
{
|
||||||
IdleEventDispatcher(L"[Timeout]");
|
IdleEventDispatcher(L"[Timeout]");
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::Ping()
|
void wxAppWithHelpers::Ping()
|
||||||
{
|
{
|
||||||
pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested.");
|
pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested.");
|
||||||
|
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
pxActionEvent evt(sync);
|
pxActionEvent evt(sync);
|
||||||
AddIdleEvent(evt);
|
AddIdleEvent(evt);
|
||||||
sync.WaitForResult();
|
sync.WaitForResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::PostCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam)
|
void wxAppWithHelpers::PostCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||||
{
|
{
|
||||||
wxCommandEvent evt(evtType);
|
wxCommandEvent evt(evtType);
|
||||||
evt.SetClientData(clientData);
|
evt.SetClientData(clientData);
|
||||||
evt.SetInt(intParam);
|
evt.SetInt(intParam);
|
||||||
evt.SetExtraLong(longParam);
|
evt.SetExtraLong(longParam);
|
||||||
evt.SetString(stringParam);
|
evt.SetString(stringParam);
|
||||||
AddPendingEvent(evt);
|
AddPendingEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString &stringParam)
|
void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||||
{
|
{
|
||||||
PostCommand(NULL, evtType, intParam, longParam, stringParam);
|
PostCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
sptr wxAppWithHelpers::ProcessCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam)
|
sptr wxAppWithHelpers::ProcessCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||||
{
|
{
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
pxSynchronousCommandEvent evt(sync, evtType);
|
pxSynchronousCommandEvent evt(sync, evtType);
|
||||||
|
|
||||||
evt.SetClientData(clientData);
|
evt.SetClientData(clientData);
|
||||||
evt.SetInt(intParam);
|
evt.SetInt(intParam);
|
||||||
evt.SetExtraLong(longParam);
|
evt.SetExtraLong(longParam);
|
||||||
evt.SetString(stringParam);
|
evt.SetString(stringParam);
|
||||||
AddPendingEvent(evt);
|
AddPendingEvent(evt);
|
||||||
sync.WaitForResult();
|
sync.WaitForResult();
|
||||||
|
|
||||||
return sync.return_value;
|
return sync.return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString &stringParam)
|
sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||||
{
|
{
|
||||||
return ProcessCommand(NULL, evtType, intParam, longParam, stringParam);
|
return ProcessCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::PostAction(const pxActionEvent &evt)
|
void wxAppWithHelpers::PostAction(const pxActionEvent& evt)
|
||||||
{
|
{
|
||||||
PostEvent(evt);
|
PostEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::ProcessAction(pxActionEvent &evt)
|
void wxAppWithHelpers::ProcessAction(pxActionEvent& evt)
|
||||||
{
|
{
|
||||||
if (!wxThread::IsMain()) {
|
if (!wxThread::IsMain())
|
||||||
SynchronousActionState sync;
|
{
|
||||||
evt.SetSyncState(sync);
|
SynchronousActionState sync;
|
||||||
AddPendingEvent(evt);
|
evt.SetSyncState(sync);
|
||||||
sync.WaitForResult();
|
AddPendingEvent(evt);
|
||||||
} else
|
sync.WaitForResult();
|
||||||
evt._DoInvokeEvent();
|
}
|
||||||
|
else
|
||||||
|
evt._DoInvokeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void wxAppWithHelpers::DeleteObject(BaseDeletableObject &obj)
|
void wxAppWithHelpers::DeleteObject(BaseDeletableObject& obj)
|
||||||
{
|
{
|
||||||
pxAssert(!obj.IsBeingDeleted());
|
pxAssert(!obj.IsBeingDeleted());
|
||||||
wxCommandEvent evt(pxEvt_DeleteObject);
|
wxCommandEvent evt(pxEvt_DeleteObject);
|
||||||
evt.SetClientData((void *)&obj);
|
evt.SetClientData((void*)&obj);
|
||||||
AddIdleEvent(evt);
|
AddIdleEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::DeleteThread(pxThread &obj)
|
void wxAppWithHelpers::DeleteThread(pxThread& obj)
|
||||||
{
|
{
|
||||||
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
|
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
|
||||||
wxCommandEvent evt(pxEvt_DeleteThread);
|
wxCommandEvent evt(pxEvt_DeleteThread);
|
||||||
evt.SetClientData((void *)&obj);
|
evt.SetClientData((void*)&obj);
|
||||||
AddIdleEvent(evt);
|
AddIdleEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppWithHelpers::OnInit()
|
bool wxAppWithHelpers::OnInit()
|
||||||
{
|
{
|
||||||
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
|
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
|
||||||
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
|
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
|
||||||
|
|
||||||
Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this);
|
Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this);
|
||||||
|
|
||||||
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this);
|
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this);
|
||||||
Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
|
Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
|
||||||
|
|
||||||
Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this);
|
Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this);
|
||||||
|
|
||||||
Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId());
|
Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId());
|
||||||
|
|
||||||
return _parent::OnInit();
|
return _parent::OnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnInvokeAction(pxActionEvent &evt)
|
void wxAppWithHelpers::OnInvokeAction(pxActionEvent& evt)
|
||||||
{
|
{
|
||||||
evt._DoInvokeEvent(); // wow this is easy!
|
evt._DoInvokeEvent(); // wow this is easy!
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt)
|
void wxAppWithHelpers::OnDeleteObject(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
if (evt.GetClientData() == NULL)
|
if (evt.GetClientData() == NULL)
|
||||||
return;
|
return;
|
||||||
delete (BaseDeletableObject *)evt.GetClientData();
|
delete (BaseDeletableObject*)evt.GetClientData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// In theory we create a Pcsx2App object which inherit from wxAppWithHelpers,
|
// In theory we create a Pcsx2App object which inherit from wxAppWithHelpers,
|
||||||
|
@ -648,35 +674,36 @@ void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt)
|
||||||
// be called first. This constructor will build some wx objects (here wxTimer)
|
// be called first. This constructor will build some wx objects (here wxTimer)
|
||||||
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
|
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
|
||||||
// called instead
|
// called instead
|
||||||
wxAppTraits *wxAppWithHelpers::CreateTraits()
|
wxAppTraits* wxAppWithHelpers::CreateTraits()
|
||||||
{
|
{
|
||||||
return new Pcsx2AppTraits;
|
return new Pcsx2AppTraits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
|
// Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
|
||||||
// (thus we have a fairly automatic threaded exception system!)
|
// (thus we have a fairly automatic threaded exception system!)
|
||||||
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent &evt)
|
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
std::unique_ptr<pxThread> thr((pxThread *)evt.GetClientData());
|
std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
|
||||||
if (!thr) {
|
if (!thr)
|
||||||
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
{
|
||||||
return;
|
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
|
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
|
||||||
thr->RethrowException();
|
thr->RethrowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxAppWithHelpers::wxAppWithHelpers()
|
wxAppWithHelpers::wxAppWithHelpers()
|
||||||
: m_IdleEventTimer(this)
|
: m_IdleEventTimer(this)
|
||||||
{
|
{
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
// This variable assignment ensures that MSVC links in the TLS setup stubs even in
|
// This variable assignment ensures that MSVC links in the TLS setup stubs even in
|
||||||
// full optimization builds. Without it, DLLs that use TLS won't work because the
|
// full optimization builds. Without it, DLLs that use TLS won't work because the
|
||||||
// FS segment register won't have been initialized by the main exe, due to tls_insurance
|
// FS segment register won't have been initialized by the main exe, due to tls_insurance
|
||||||
// being optimized away >_< --air
|
// being optimized away >_< --air
|
||||||
|
|
||||||
static thread_local int tls_insurance = 0;
|
static thread_local int tls_insurance = 0;
|
||||||
tls_insurance = 1;
|
tls_insurance = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,10 @@ class pxSynchronousCommandEvent;
|
||||||
|
|
||||||
class ConsoleLogSource_App : public ConsoleLogSource
|
class ConsoleLogSource_App : public ConsoleLogSource
|
||||||
{
|
{
|
||||||
typedef ConsoleLogSource _parent;
|
typedef ConsoleLogSource _parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleLogSource_App();
|
ConsoleLogSource_App();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ConsoleLogSource_App pxConLog_App;
|
extern ConsoleLogSource_App pxConLog_App;
|
||||||
|
@ -49,97 +49,97 @@ extern ConsoleLogSource_App pxConLog_App;
|
||||||
class ModalButtonPanel : public wxPanelWithHelpers
|
class ModalButtonPanel : public wxPanelWithHelpers
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ModalButtonPanel(wxWindow *window, const MsgButtons &buttons);
|
ModalButtonPanel(wxWindow* window, const MsgButtons& buttons);
|
||||||
virtual ~ModalButtonPanel() = default;
|
virtual ~ModalButtonPanel() = default;
|
||||||
|
|
||||||
virtual void AddActionButton(wxWindowID id);
|
virtual void AddActionButton(wxWindowID id);
|
||||||
virtual void AddCustomButton(wxWindowID id, const wxString &label);
|
virtual void AddCustomButton(wxWindowID id, const wxString& label);
|
||||||
|
|
||||||
virtual void OnActionButtonClicked(wxCommandEvent &evt);
|
virtual void OnActionButtonClicked(wxCommandEvent& evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<wxEvent *> wxEventList;
|
typedef std::list<wxEvent*> wxEventList;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// wxAppWithHelpers
|
// wxAppWithHelpers
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class wxAppWithHelpers : public wxApp
|
class wxAppWithHelpers : public wxApp
|
||||||
{
|
{
|
||||||
typedef wxApp _parent;
|
typedef wxApp _parent;
|
||||||
|
|
||||||
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
|
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxEventList m_IdleEventQueue;
|
wxEventList m_IdleEventQueue;
|
||||||
Threading::MutexRecursive m_IdleEventMutex;
|
Threading::MutexRecursive m_IdleEventMutex;
|
||||||
wxTimer m_IdleEventTimer;
|
wxTimer m_IdleEventTimer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxAppWithHelpers();
|
wxAppWithHelpers();
|
||||||
virtual ~wxAppWithHelpers() {}
|
virtual ~wxAppWithHelpers() {}
|
||||||
|
|
||||||
wxAppTraits *CreateTraits();
|
wxAppTraits* CreateTraits();
|
||||||
|
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
|
|
||||||
void DeleteObject(BaseDeletableObject &obj);
|
void DeleteObject(BaseDeletableObject& obj);
|
||||||
void DeleteObject(BaseDeletableObject *obj)
|
void DeleteObject(BaseDeletableObject* obj)
|
||||||
{
|
{
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
return;
|
return;
|
||||||
DeleteObject(*obj);
|
DeleteObject(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteThread(Threading::pxThread &obj);
|
void DeleteThread(Threading::pxThread& obj);
|
||||||
void DeleteThread(Threading::pxThread *obj)
|
void DeleteThread(Threading::pxThread* obj)
|
||||||
{
|
{
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
return;
|
return;
|
||||||
DeleteThread(*obj);
|
DeleteThread(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
void PostCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||||
void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||||
void PostMethod(FnType_Void *method);
|
void PostMethod(FnType_Void* method);
|
||||||
void PostIdleMethod(FnType_Void *method);
|
void PostIdleMethod(FnType_Void* method);
|
||||||
void ProcessMethod(FnType_Void *method);
|
void ProcessMethod(FnType_Void* method);
|
||||||
|
|
||||||
bool Rpc_TryInvoke(FnType_Void *method);
|
bool Rpc_TryInvoke(FnType_Void* method);
|
||||||
bool Rpc_TryInvokeAsync(FnType_Void *method);
|
bool Rpc_TryInvokeAsync(FnType_Void* method);
|
||||||
|
|
||||||
sptr ProcessCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
sptr ProcessCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||||
sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||||
|
|
||||||
void ProcessAction(pxActionEvent &evt);
|
void ProcessAction(pxActionEvent& evt);
|
||||||
void PostAction(const pxActionEvent &evt);
|
void PostAction(const pxActionEvent& evt);
|
||||||
|
|
||||||
void Ping();
|
void Ping();
|
||||||
bool OnInit();
|
bool OnInit();
|
||||||
//int OnExit();
|
//int OnExit();
|
||||||
|
|
||||||
void AddIdleEvent(const wxEvent &evt);
|
void AddIdleEvent(const wxEvent& evt);
|
||||||
|
|
||||||
void PostEvent(const wxEvent &evt);
|
void PostEvent(const wxEvent& evt);
|
||||||
bool ProcessEvent(wxEvent &evt);
|
bool ProcessEvent(wxEvent& evt);
|
||||||
bool ProcessEvent(wxEvent *evt);
|
bool ProcessEvent(wxEvent* evt);
|
||||||
|
|
||||||
bool ProcessEvent(pxActionEvent &evt);
|
bool ProcessEvent(pxActionEvent& evt);
|
||||||
bool ProcessEvent(pxActionEvent *evt);
|
bool ProcessEvent(pxActionEvent* evt);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void IdleEventDispatcher(const wxChar *action = wxEmptyString);
|
void IdleEventDispatcher(const wxChar* action = wxEmptyString);
|
||||||
|
|
||||||
void OnIdleEvent(wxIdleEvent &evt);
|
void OnIdleEvent(wxIdleEvent& evt);
|
||||||
void OnStartIdleEventTimer(wxCommandEvent &evt);
|
void OnStartIdleEventTimer(wxCommandEvent& evt);
|
||||||
void OnIdleEventTimeout(wxTimerEvent &evt);
|
void OnIdleEventTimeout(wxTimerEvent& evt);
|
||||||
void OnDeleteObject(wxCommandEvent &evt);
|
void OnDeleteObject(wxCommandEvent& evt);
|
||||||
void OnDeleteThread(wxCommandEvent &evt);
|
void OnDeleteThread(wxCommandEvent& evt);
|
||||||
void OnSynchronousCommand(pxSynchronousCommandEvent &evt);
|
void OnSynchronousCommand(pxSynchronousCommandEvent& evt);
|
||||||
void OnInvokeAction(pxActionEvent &evt);
|
void OnInvokeAction(pxActionEvent& evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
extern int ShowModal(BaseMessageBoxEvent &evt);
|
extern int ShowModal(BaseMessageBoxEvent& evt);
|
||||||
extern int ShowModal(const wxString &title, const wxString &content, const MsgButtons &buttons);
|
extern int ShowModal(const wxString& title, const wxString& content, const MsgButtons& buttons);
|
||||||
}
|
} // namespace Msgbox
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
// which require wxCore, see wxGuiTools.h
|
// which require wxCore, see wxGuiTools.h
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
extern void pxExplore(const wxString &path);
|
extern void pxExplore(const wxString& path);
|
||||||
extern void pxExplore(const char *path);
|
extern void pxExplore(const char* path);
|
||||||
|
|
||||||
extern void pxLaunch(const wxString &path);
|
extern void pxLaunch(const wxString& path);
|
||||||
extern void pxLaunch(const char *path);
|
extern void pxLaunch(const char* path);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// wxDoNotLogInThisScope
|
// wxDoNotLogInThisScope
|
||||||
|
@ -44,28 +44,28 @@ extern void pxLaunch(const char *path);
|
||||||
//
|
//
|
||||||
class wxDoNotLogInThisScope
|
class wxDoNotLogInThisScope
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject(wxDoNotLogInThisScope);
|
DeclareNoncopyableObject(wxDoNotLogInThisScope);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_prev;
|
bool m_prev;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxDoNotLogInThisScope()
|
wxDoNotLogInThisScope()
|
||||||
{
|
{
|
||||||
m_prev = wxLog::EnableLogging(false);
|
m_prev = wxLog::EnableLogging(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~wxDoNotLogInThisScope()
|
virtual ~wxDoNotLogInThisScope()
|
||||||
{
|
{
|
||||||
wxLog::EnableLogging(m_prev);
|
wxLog::EnableLogging(m_prev);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern wxString pxReadLine(wxInputStream &input);
|
extern wxString pxReadLine(wxInputStream& input);
|
||||||
extern void pxReadLine(wxInputStream &input, wxString &dest);
|
extern void pxReadLine(wxInputStream& input, wxString& dest);
|
||||||
extern void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed);
|
extern void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed);
|
||||||
extern bool pxReadLine(wxInputStream &input, std::string &dest);
|
extern bool pxReadLine(wxInputStream& input, std::string& dest);
|
||||||
extern void pxWriteLine(wxOutputStream &output);
|
extern void pxWriteLine(wxOutputStream& output);
|
||||||
extern void pxWriteLine(wxOutputStream &output, const wxString &text);
|
extern void pxWriteLine(wxOutputStream& output, const wxString& text);
|
||||||
extern void pxWriteMultiline(wxOutputStream &output, const wxString &src);
|
extern void pxWriteMultiline(wxOutputStream& output, const wxString& src);
|
||||||
|
|
|
@ -22,171 +22,173 @@
|
||||||
#include <wx/display.h>
|
#include <wx/display.h>
|
||||||
|
|
||||||
const pxAlignmentType
|
const pxAlignmentType
|
||||||
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
|
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
|
||||||
pxCenter = pxCentre,
|
pxCenter = pxCentre,
|
||||||
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
|
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
|
||||||
|
|
||||||
pxAlignLeft = {pxAlignmentType::Left},
|
pxAlignLeft = {pxAlignmentType::Left},
|
||||||
pxAlignRight = {pxAlignmentType::Right},
|
pxAlignRight = {pxAlignmentType::Right},
|
||||||
pxAlignTop = {pxAlignmentType::Top},
|
pxAlignTop = {pxAlignmentType::Top},
|
||||||
pxAlignBottom = {pxAlignmentType::Bottom};
|
pxAlignBottom = {pxAlignmentType::Bottom};
|
||||||
|
|
||||||
const pxStretchType
|
const pxStretchType
|
||||||
pxShrink = {pxStretchType::Shrink},
|
pxShrink = {pxStretchType::Shrink},
|
||||||
pxExpand = {pxStretchType::Expand},
|
pxExpand = {pxStretchType::Expand},
|
||||||
pxShaped = {pxStretchType::Shaped},
|
pxShaped = {pxStretchType::Shaped},
|
||||||
pxReserveHidden = {pxStretchType::ReserveHidden},
|
pxReserveHidden = {pxStretchType::ReserveHidden},
|
||||||
pxFixedMinimum = {pxStretchType::FixedMinimum};
|
pxFixedMinimum = {pxStretchType::FixedMinimum};
|
||||||
|
|
||||||
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
||||||
{
|
{
|
||||||
switch (intval) {
|
switch (intval)
|
||||||
case Centre:
|
{
|
||||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
case Centre:
|
||||||
break;
|
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
||||||
|
break;
|
||||||
|
|
||||||
case Middle:
|
case Middle:
|
||||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
|
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Left:
|
case Left:
|
||||||
flags.Left();
|
flags.Left();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Right:
|
case Right:
|
||||||
flags.Right();
|
flags.Right();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Top:
|
case Top:
|
||||||
flags.Top();
|
flags.Top();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Bottom:
|
case Bottom:
|
||||||
flags.Bottom();
|
flags.Bottom();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
|
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
|
||||||
{
|
{
|
||||||
switch (intval) {
|
switch (intval)
|
||||||
case Shrink:
|
{
|
||||||
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
case Shrink:
|
||||||
break;
|
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
||||||
|
break;
|
||||||
|
|
||||||
case Expand:
|
case Expand:
|
||||||
flags.Expand();
|
flags.Expand();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Shaped:
|
case Shaped:
|
||||||
flags.Shaped();
|
flags.Shaped();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ReserveHidden:
|
case ReserveHidden:
|
||||||
flags.ReserveSpaceEvenIfHidden();
|
flags.ReserveSpaceEvenIfHidden();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FixedMinimum:
|
case FixedMinimum:
|
||||||
flags.FixedMinSize();
|
flags.FixedMinSize();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case Tile:
|
//case Tile:
|
||||||
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
|
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
|
||||||
//break;
|
//break;
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags operator&(const wxSizerFlags &_flgs, const wxSizerFlags &_flgs2)
|
wxSizerFlags operator&(const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2)
|
||||||
{
|
{
|
||||||
//return align.Apply( _flgs );
|
//return align.Apply( _flgs );
|
||||||
wxSizerFlags retval;
|
wxSizerFlags retval;
|
||||||
|
|
||||||
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
|
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
|
||||||
|
|
||||||
retval.Align(allflags & wxALIGN_MASK);
|
retval.Align(allflags & wxALIGN_MASK);
|
||||||
if (allflags & wxEXPAND)
|
if (allflags & wxEXPAND)
|
||||||
retval.Expand();
|
retval.Expand();
|
||||||
if (allflags & wxSHAPED)
|
if (allflags & wxSHAPED)
|
||||||
retval.Shaped();
|
retval.Shaped();
|
||||||
if (allflags & wxFIXED_MINSIZE)
|
if (allflags & wxFIXED_MINSIZE)
|
||||||
retval.FixedMinSize();
|
retval.FixedMinSize();
|
||||||
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
|
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
|
||||||
retval.ReserveSpaceEvenIfHidden();
|
retval.ReserveSpaceEvenIfHidden();
|
||||||
|
|
||||||
// Compounding borders is probably a fair approach:
|
// Compounding borders is probably a fair approach:
|
||||||
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
|
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
|
||||||
|
|
||||||
// Compounding proportions works as well, I figure.
|
// Compounding proportions works as well, I figure.
|
||||||
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
|
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Reference/Handle versions!
|
// Reference/Handle versions!
|
||||||
|
|
||||||
void operator+=(wxSizer &target, wxWindow *src)
|
void operator+=(wxSizer& target, wxWindow* src)
|
||||||
{
|
{
|
||||||
target.Add(src);
|
target.Add(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, wxSizer *src)
|
void operator+=(wxSizer& target, wxSizer* src)
|
||||||
{
|
{
|
||||||
target.Add(src);
|
target.Add(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, wxWindow &src)
|
void operator+=(wxSizer& target, wxWindow& src)
|
||||||
{
|
{
|
||||||
target.Add(&src);
|
target.Add(&src);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, wxSizer &src)
|
void operator+=(wxSizer& target, wxSizer& src)
|
||||||
{
|
{
|
||||||
target.Add(&src);
|
target.Add(&src);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, int spacer)
|
void operator+=(wxSizer& target, int spacer)
|
||||||
{
|
{
|
||||||
target.AddSpacer(spacer);
|
target.AddSpacer(spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer &target, const pxStretchSpacer &spacer)
|
void operator+=(wxSizer& target, const pxStretchSpacer& spacer)
|
||||||
{
|
{
|
||||||
target.AddStretchSpacer(spacer.proportion);
|
target.AddStretchSpacer(spacer.proportion);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxWindow &target, int spacer)
|
void operator+=(wxWindow& target, int spacer)
|
||||||
{
|
{
|
||||||
if (!pxAssert(target.GetSizer() != NULL))
|
if (!pxAssert(target.GetSizer() != NULL))
|
||||||
return;
|
return;
|
||||||
target.GetSizer()->AddSpacer(spacer);
|
target.GetSizer()->AddSpacer(spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxWindow &target, const pxStretchSpacer &spacer)
|
void operator+=(wxWindow& target, const pxStretchSpacer& spacer)
|
||||||
{
|
{
|
||||||
if (!pxAssert(target.GetSizer() != NULL))
|
if (!pxAssert(target.GetSizer() != NULL))
|
||||||
return;
|
return;
|
||||||
target.GetSizer()->AddStretchSpacer(spacer.proportion);
|
target.GetSizer()->AddStretchSpacer(spacer.proportion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Pointer versions! (note that C++ requires one of the two operator params be a
|
// Pointer versions! (note that C++ requires one of the two operator params be a
|
||||||
// "poper" object type (non-pointer), so that's why there's only a couple of these.
|
// "poper" object type (non-pointer), so that's why there's only a couple of these.
|
||||||
|
|
||||||
void operator+=(wxSizer *target, wxWindow &src)
|
void operator+=(wxSizer* target, wxWindow& src)
|
||||||
{
|
{
|
||||||
if (!pxAssert(target != NULL))
|
if (!pxAssert(target != NULL))
|
||||||
return;
|
return;
|
||||||
target->Add(&src);
|
target->Add(&src);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator+=(wxSizer *target, wxSizer &src)
|
void operator+=(wxSizer* target, wxSizer& src)
|
||||||
{
|
{
|
||||||
if (!pxAssert(target != NULL))
|
if (!pxAssert(target != NULL))
|
||||||
return;
|
return;
|
||||||
target->Add(&src);
|
target->Add(&src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -194,23 +196,23 @@ void operator+=(wxSizer *target, wxSizer &src)
|
||||||
// Returns FALSE if the window position is considered invalid, which means that it's title
|
// Returns FALSE if the window position is considered invalid, which means that it's title
|
||||||
// bar is most likely not easily grabble. Such a window should be moved to a valid or
|
// bar is most likely not easily grabble. Such a window should be moved to a valid or
|
||||||
// default position.
|
// default position.
|
||||||
bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos)
|
bool pxIsValidWindowPosition(const wxWindow& window, const wxPoint& windowPos)
|
||||||
{
|
{
|
||||||
// The height of the window is only revlevant to the height of a title bar, which is
|
// The height of the window is only revlevant to the height of a title bar, which is
|
||||||
// all we need visible for the user to be able to drag the window into view. But
|
// all we need visible for the user to be able to drag the window into view. But
|
||||||
// there's no way to get that info from wx, so we'll just have to guesstimate...
|
// there's no way to get that info from wx, so we'll just have to guesstimate...
|
||||||
|
|
||||||
const wxSize sizeMatters(window.GetSize().GetWidth(), 32);
|
const wxSize sizeMatters(window.GetSize().GetWidth(), 32);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
|
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
|
||||||
{
|
{
|
||||||
const auto rect = wxDisplay(i).GetGeometry();
|
const auto rect = wxDisplay(i).GetGeometry();
|
||||||
|
|
||||||
if (rect.Contains(wxRect(windowPos, sizeMatters)))
|
if (rect.Contains(wxRect(windowPos, sizeMatters)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the area of the screen, which can be used to enforce a valid zone for
|
// Retrieves the area of the screen, which can be used to enforce a valid zone for
|
||||||
|
@ -218,7 +220,7 @@ bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos)
|
||||||
// is the resolution of the desktop).
|
// is the resolution of the desktop).
|
||||||
wxRect wxGetDisplayArea()
|
wxRect wxGetDisplayArea()
|
||||||
{
|
{
|
||||||
return wxRect(wxPoint(), wxGetDisplaySize());
|
return wxRect(wxPoint(), wxGetDisplaySize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -234,17 +236,17 @@ wxRect wxGetDisplayArea()
|
||||||
//
|
//
|
||||||
wxSizerFlags pxSizerFlags::StdSpace()
|
wxSizerFlags pxSizerFlags::StdSpace()
|
||||||
{
|
{
|
||||||
return wxSizerFlags().Border(wxALL, StdPadding);
|
return wxSizerFlags().Border(wxALL, StdPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags pxSizerFlags::StdCenter()
|
wxSizerFlags pxSizerFlags::StdCenter()
|
||||||
{
|
{
|
||||||
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
|
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags pxSizerFlags::StdExpand()
|
wxSizerFlags pxSizerFlags::StdExpand()
|
||||||
{
|
{
|
||||||
return StdSpace().Expand();
|
return StdSpace().Expand();
|
||||||
}
|
}
|
||||||
|
|
||||||
// A good sizer flags setting for top-level static boxes or top-level picture boxes.
|
// A good sizer flags setting for top-level static boxes or top-level picture boxes.
|
||||||
|
@ -252,7 +254,7 @@ wxSizerFlags pxSizerFlags::StdExpand()
|
||||||
// manually by using a spacer.
|
// manually by using a spacer.
|
||||||
wxSizerFlags pxSizerFlags::TopLevelBox()
|
wxSizerFlags pxSizerFlags::TopLevelBox()
|
||||||
{
|
{
|
||||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand();
|
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flags intended for use on grouped StaticBox controls. These flags are ideal for
|
// Flags intended for use on grouped StaticBox controls. These flags are ideal for
|
||||||
|
@ -261,9 +263,9 @@ wxSizerFlags pxSizerFlags::TopLevelBox()
|
||||||
// "tight").
|
// "tight").
|
||||||
wxSizerFlags pxSizerFlags::SubGroup()
|
wxSizerFlags pxSizerFlags::SubGroup()
|
||||||
{
|
{
|
||||||
// Groups look better with a slightly smaller margin than standard.
|
// Groups look better with a slightly smaller margin than standard.
|
||||||
// (basically this accounts for the group's frame)
|
// (basically this accounts for the group's frame)
|
||||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
|
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This force-aligns the std button sizer to the right, where (at least) us win32 platform
|
// This force-aligns the std button sizer to the right, where (at least) us win32 platform
|
||||||
|
@ -271,20 +273,20 @@ wxSizerFlags pxSizerFlags::SubGroup()
|
||||||
// just because it's *not* where win32 sticks it. Too bad!
|
// just because it's *not* where win32 sticks it. Too bad!
|
||||||
wxSizerFlags pxSizerFlags::StdButton()
|
wxSizerFlags pxSizerFlags::StdButton()
|
||||||
{
|
{
|
||||||
return pxBorder().Align(wxALIGN_RIGHT);
|
return pxBorder().Align(wxALIGN_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags pxSizerFlags::Checkbox()
|
wxSizerFlags pxSizerFlags::Checkbox()
|
||||||
{
|
{
|
||||||
return StdExpand();
|
return StdExpand();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxSizerFlags::SetBestPadding()
|
void pxSizerFlags::SetBestPadding()
|
||||||
{
|
{
|
||||||
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
|
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
|
||||||
StdPadding = 4;
|
StdPadding = 4;
|
||||||
else
|
else
|
||||||
StdPadding = 1;
|
StdPadding = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -293,44 +295,44 @@ void pxSizerFlags::SetBestPadding()
|
||||||
|
|
||||||
static bool is_cjk_char(const uint ch)
|
static bool is_cjk_char(const uint ch)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* You can check these range at http://unicode.org/charts/
|
* You can check these range at http://unicode.org/charts/
|
||||||
* see the "East Asian Scripts" part.
|
* see the "East Asian Scripts" part.
|
||||||
* Notice that not all characters in that part is still in use today, so don't list them all here.
|
* Notice that not all characters in that part is still in use today, so don't list them all here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
|
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
|
||||||
// characters are used today.
|
// characters are used today.
|
||||||
|
|
||||||
if (ch < 0x2e80)
|
if (ch < 0x2e80)
|
||||||
return false; // shortcut for common non-CJK
|
return false; // shortcut for common non-CJK
|
||||||
|
|
||||||
return
|
return
|
||||||
// Han Ideographs: all except Supplement
|
// Han Ideographs: all except Supplement
|
||||||
(ch >= 0x4e00 && ch < 0x9fcf) ||
|
(ch >= 0x4e00 && ch < 0x9fcf) ||
|
||||||
(ch >= 0x3400 && ch < 0x4dbf) ||
|
(ch >= 0x3400 && ch < 0x4dbf) ||
|
||||||
(ch >= 0x20000 && ch < 0x2a6df) ||
|
(ch >= 0x20000 && ch < 0x2a6df) ||
|
||||||
(ch >= 0xf900 && ch < 0xfaff) ||
|
(ch >= 0xf900 && ch < 0xfaff) ||
|
||||||
(ch >= 0x3190 && ch < 0x319f) ||
|
(ch >= 0x3190 && ch < 0x319f) ||
|
||||||
|
|
||||||
// Radicals: all except Ideographic Description
|
// Radicals: all except Ideographic Description
|
||||||
(ch >= 0x2e80 && ch < 0x2eff) ||
|
(ch >= 0x2e80 && ch < 0x2eff) ||
|
||||||
(ch >= 0x2f00 && ch < 0x2fdf) ||
|
(ch >= 0x2f00 && ch < 0x2fdf) ||
|
||||||
(ch >= 0x31c0 && ch < 0x31ef) ||
|
(ch >= 0x31c0 && ch < 0x31ef) ||
|
||||||
|
|
||||||
// Chinese-specific: Bopomofo
|
// Chinese-specific: Bopomofo
|
||||||
(ch >= 0x3000 && ch < 0x303f) ||
|
(ch >= 0x3000 && ch < 0x303f) ||
|
||||||
|
|
||||||
// Japanese-specific: Halfwidth Katakana
|
// Japanese-specific: Halfwidth Katakana
|
||||||
(ch >= 0xff00 && ch < 0xffef) ||
|
(ch >= 0xff00 && ch < 0xffef) ||
|
||||||
|
|
||||||
// Japanese-specific: Hiragana, Katakana
|
// Japanese-specific: Hiragana, Katakana
|
||||||
(ch >= 0x3040 && ch <= 0x309f) ||
|
(ch >= 0x3040 && ch <= 0x309f) ||
|
||||||
(ch >= 0x30a0 && ch <= 0x30ff) ||
|
(ch >= 0x30a0 && ch <= 0x30ff) ||
|
||||||
|
|
||||||
// Korean-specific: Hangul Syllables, Halfwidth Jamo
|
// Korean-specific: Hangul Syllables, Halfwidth Jamo
|
||||||
(ch >= 0xac00 && ch < 0xd7af) ||
|
(ch >= 0xac00 && ch < 0xd7af) ||
|
||||||
(ch >= 0xff00 && ch < 0xffef);
|
(ch >= 0xff00 && ch < 0xffef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -350,7 +352,7 @@ static bool is_cjk_char(const uint ch)
|
||||||
*/
|
*/
|
||||||
static bool no_break_after(const uint ch)
|
static bool no_break_after(const uint ch)
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
/**
|
/**
|
||||||
* don't break after these Japanese/Chinese characters
|
* don't break after these Japanese/Chinese characters
|
||||||
|
@ -366,14 +368,14 @@ static bool no_break_after(const uint ch)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool no_break_before(const uint ch)
|
static bool no_break_before(const uint ch)
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
/**
|
/**
|
||||||
* don't break before these Japanese characters
|
* don't break before these Japanese characters
|
||||||
|
@ -403,84 +405,94 @@ static bool no_break_before(const uint ch)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxTextWrapperBase &pxTextWrapperBase::Wrap(const wxWindow &win, const wxString &text, int widthMax)
|
pxTextWrapperBase& pxTextWrapperBase::Wrap(const wxWindow& win, const wxString& text, int widthMax)
|
||||||
{
|
{
|
||||||
if (text.empty())
|
if (text.empty())
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
bool wasWrapped = false;
|
bool wasWrapped = false;
|
||||||
|
|
||||||
wxString line;
|
wxString line;
|
||||||
line.reserve(text.length() + 12);
|
line.reserve(text.length() + 12);
|
||||||
|
|
||||||
wxString::const_iterator lastSpace = text.end();
|
wxString::const_iterator lastSpace = text.end();
|
||||||
wxString::const_iterator lineStart = text.begin();
|
wxString::const_iterator lineStart = text.begin();
|
||||||
for (wxString::const_iterator p = lineStart;; ++p) {
|
for (wxString::const_iterator p = lineStart;; ++p)
|
||||||
if (IsStartOfNewLine()) {
|
{
|
||||||
OnNewLine();
|
if (IsStartOfNewLine())
|
||||||
|
{
|
||||||
|
OnNewLine();
|
||||||
|
|
||||||
lastSpace = text.end();
|
lastSpace = text.end();
|
||||||
lineStart = p;
|
lineStart = p;
|
||||||
|
|
||||||
if (wasWrapped)
|
if (wasWrapped)
|
||||||
line = m_indent;
|
line = m_indent;
|
||||||
else
|
else
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p == text.end() || *p == L'\n') {
|
if (p == text.end() || *p == L'\n')
|
||||||
wasWrapped = false;
|
{
|
||||||
DoOutputLine(line);
|
wasWrapped = false;
|
||||||
|
DoOutputLine(line);
|
||||||
|
|
||||||
if (p == text.end())
|
if (p == text.end())
|
||||||
break;
|
break;
|
||||||
} else { // not EOL
|
}
|
||||||
if (is_cjk_char(*p)) {
|
else
|
||||||
if (!no_break_before(*p)) {
|
{ // not EOL
|
||||||
if (p == lineStart || !no_break_after(*(p - 1)))
|
if (is_cjk_char(*p))
|
||||||
lastSpace = p;
|
{
|
||||||
}
|
if (!no_break_before(*p))
|
||||||
} else if (*p == L' ' || *p == L',' || *p == L'/')
|
{
|
||||||
lastSpace = p;
|
if (p == lineStart || !no_break_after(*(p - 1)))
|
||||||
|
lastSpace = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*p == L' ' || *p == L',' || *p == L'/')
|
||||||
|
lastSpace = p;
|
||||||
|
|
||||||
line += *p;
|
line += *p;
|
||||||
|
|
||||||
if (widthMax >= 0 && lastSpace != text.end()) {
|
if (widthMax >= 0 && lastSpace != text.end())
|
||||||
int width;
|
{
|
||||||
win.GetTextExtent(line, &width, NULL);
|
int width;
|
||||||
|
win.GetTextExtent(line, &width, NULL);
|
||||||
|
|
||||||
if (width > widthMax) {
|
if (width > widthMax)
|
||||||
wasWrapped = true;
|
{
|
||||||
|
wasWrapped = true;
|
||||||
|
|
||||||
// remove the last word from this line
|
// remove the last word from this line
|
||||||
line.erase(lastSpace - lineStart, p + 1 - lineStart);
|
line.erase(lastSpace - lineStart, p + 1 - lineStart);
|
||||||
DoOutputLine(line);
|
DoOutputLine(line);
|
||||||
|
|
||||||
// go back to the last word of this line which we didn't
|
// go back to the last word of this line which we didn't
|
||||||
// output yet
|
// output yet
|
||||||
p = lastSpace;
|
p = lastSpace;
|
||||||
|
|
||||||
if (*p != L' ')
|
if (*p != L' ')
|
||||||
p--;
|
p--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//else: no wrapping at all or impossible to wrap
|
//else: no wrapping at all or impossible to wrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxTextWrapperBase::DoOutputLine(const wxString &line)
|
void pxTextWrapperBase::DoOutputLine(const wxString& line)
|
||||||
{
|
{
|
||||||
OnOutputLine(line);
|
OnOutputLine(line);
|
||||||
m_linecount++;
|
m_linecount++;
|
||||||
m_eol = true;
|
m_eol = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function is a destructive inspector: when it returns true it also
|
// this function is a destructive inspector: when it returns true it also
|
||||||
|
@ -488,34 +500,34 @@ void pxTextWrapperBase::DoOutputLine(const wxString &line)
|
||||||
// more
|
// more
|
||||||
bool pxTextWrapperBase::IsStartOfNewLine()
|
bool pxTextWrapperBase::IsStartOfNewLine()
|
||||||
{
|
{
|
||||||
if (!m_eol)
|
if (!m_eol)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_eol = false;
|
m_eol = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow &win, const wxString &text, int widthMax)
|
pxTextWrapper& pxTextWrapper::Wrap(const wxWindow& win, const wxString& text, int widthMax)
|
||||||
{
|
{
|
||||||
_parent::Wrap(win, text, widthMax);
|
_parent::Wrap(win, text, widthMax);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow *win, const wxString &text, int widthMax)
|
pxTextWrapper& pxTextWrapper::Wrap(const wxWindow* win, const wxString& text, int widthMax)
|
||||||
{
|
{
|
||||||
if (win)
|
if (win)
|
||||||
_parent::Wrap(*win, text, widthMax);
|
_parent::Wrap(*win, text, widthMax);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxTextWrapper::OnOutputLine(const wxString &line)
|
void pxTextWrapper::OnOutputLine(const wxString& line)
|
||||||
{
|
{
|
||||||
m_text += line;
|
m_text += line;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxTextWrapper::OnNewLine()
|
void pxTextWrapper::OnNewLine()
|
||||||
{
|
{
|
||||||
m_text += L'\n';
|
m_text += L'\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -527,67 +539,69 @@ BusyCursorType ScopedBusyCursor::m_defBusyType;
|
||||||
|
|
||||||
ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype)
|
ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype)
|
||||||
{
|
{
|
||||||
pxAssert(wxTheApp != NULL);
|
pxAssert(wxTheApp != NULL);
|
||||||
|
|
||||||
BusyCursorType curtype = Cursor_NotBusy;
|
BusyCursorType curtype = Cursor_NotBusy;
|
||||||
if (!m_cursorStack.empty())
|
if (!m_cursorStack.empty())
|
||||||
curtype = m_cursorStack.top();
|
curtype = m_cursorStack.top();
|
||||||
|
|
||||||
if (curtype < busytype)
|
if (curtype < busytype)
|
||||||
SetManualBusyCursor(curtype = busytype);
|
SetManualBusyCursor(curtype = busytype);
|
||||||
|
|
||||||
m_cursorStack.push(curtype);
|
m_cursorStack.push(curtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedBusyCursor::~ScopedBusyCursor()
|
ScopedBusyCursor::~ScopedBusyCursor()
|
||||||
{
|
{
|
||||||
if (!pxAssert(wxTheApp != NULL))
|
if (!pxAssert(wxTheApp != NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!pxAssert(!m_cursorStack.empty())) {
|
if (!pxAssert(!m_cursorStack.empty()))
|
||||||
SetManualBusyCursor(m_defBusyType);
|
{
|
||||||
return;
|
SetManualBusyCursor(m_defBusyType);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BusyCursorType curtype = m_cursorStack.top();
|
BusyCursorType curtype = m_cursorStack.top();
|
||||||
m_cursorStack.pop();
|
m_cursorStack.pop();
|
||||||
|
|
||||||
if (m_cursorStack.empty())
|
if (m_cursorStack.empty())
|
||||||
SetManualBusyCursor(m_defBusyType);
|
SetManualBusyCursor(m_defBusyType);
|
||||||
else if (m_cursorStack.top() != curtype)
|
else if (m_cursorStack.top() != curtype)
|
||||||
SetManualBusyCursor(m_cursorStack.top());
|
SetManualBusyCursor(m_cursorStack.top());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
|
void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
|
||||||
{
|
{
|
||||||
if (busytype == m_defBusyType)
|
if (busytype == m_defBusyType)
|
||||||
return;
|
return;
|
||||||
m_defBusyType = busytype;
|
m_defBusyType = busytype;
|
||||||
|
|
||||||
if (m_cursorStack.empty())
|
if (m_cursorStack.empty())
|
||||||
SetManualBusyCursor(busytype);
|
SetManualBusyCursor(busytype);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
|
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
|
||||||
{
|
{
|
||||||
switch (busytype) {
|
switch (busytype)
|
||||||
case Cursor_NotBusy:
|
{
|
||||||
wxSetCursor(wxNullCursor);
|
case Cursor_NotBusy:
|
||||||
break;
|
wxSetCursor(wxNullCursor);
|
||||||
case Cursor_KindaBusy:
|
break;
|
||||||
wxSetCursor(StockCursors.GetArrowWait());
|
case Cursor_KindaBusy:
|
||||||
break;
|
wxSetCursor(StockCursors.GetArrowWait());
|
||||||
case Cursor_ReallyBusy:
|
break;
|
||||||
wxSetCursor(*wxHOURGLASS_CURSOR);
|
case Cursor_ReallyBusy:
|
||||||
break;
|
wxSetCursor(*wxHOURGLASS_CURSOR);
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxCursor &MoreStockCursors::GetArrowWait()
|
const wxCursor& MoreStockCursors::GetArrowWait()
|
||||||
{
|
{
|
||||||
if (!m_arrowWait)
|
if (!m_arrowWait)
|
||||||
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
|
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
|
||||||
return *m_arrowWait;
|
return *m_arrowWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
MoreStockCursors StockCursors;
|
MoreStockCursors StockCursors;
|
||||||
|
@ -599,39 +613,39 @@ MoreStockCursors StockCursors;
|
||||||
// extends the tooltip time to the maximum possible. GTK seems to have indefinite
|
// extends the tooltip time to the maximum possible. GTK seems to have indefinite
|
||||||
// tooltips, I don't know about OS X.
|
// tooltips, I don't know about OS X.
|
||||||
|
|
||||||
void pxSetToolTip(wxWindow *wind, const wxString &src)
|
void pxSetToolTip(wxWindow* wind, const wxString& src)
|
||||||
{
|
{
|
||||||
if (wind == NULL)
|
if (wind == NULL)
|
||||||
return; // Silently ignore nulls
|
return; // Silently ignore nulls
|
||||||
wind->SetToolTip(src);
|
wind->SetToolTip(src);
|
||||||
|
|
||||||
// Make tooltips show for as long as possible on Windows. Linux (GTK) can
|
// Make tooltips show for as long as possible on Windows. Linux (GTK) can
|
||||||
// show tooltips indefinitely.
|
// show tooltips indefinitely.
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
wind->GetToolTip()->SetAutoPop(32767);
|
wind->GetToolTip()->SetAutoPop(32767);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxSetToolTip(wxWindow &wind, const wxString &src)
|
void pxSetToolTip(wxWindow& wind, const wxString& src)
|
||||||
{
|
{
|
||||||
pxSetToolTip(&wind, src);
|
pxSetToolTip(&wind, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline)
|
wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline)
|
||||||
{
|
{
|
||||||
return wxFont(
|
return wxFont(
|
||||||
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
|
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
,
|
,
|
||||||
L"Lucida Console" // better than courier new (win32 only)
|
L"Lucida Console" // better than courier new (win32 only)
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString pxGetAppName()
|
wxString pxGetAppName()
|
||||||
{
|
{
|
||||||
pxAssert(wxTheApp);
|
pxAssert(wxTheApp);
|
||||||
return wxTheApp->GetAppName();
|
return wxTheApp->GetAppName();
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue