From fc7099a9057ee962ea4fd43bf049396d86065cf0 Mon Sep 17 00:00:00 2001 From: Armada Date: Sat, 15 Jun 2013 13:21:57 +0200 Subject: [PATCH] Set the locale per-thread instead of globally when generating shaders. Add cross-compatible versions of newlocale, uselocale and freelocale. This commit fixes a rare race condition when generating shaders because setlocale is global. --- Source/Core/Common/Src/CommonFuncs.h | 39 +++++++++++++++++++ .../Core/VideoCommon/Src/PixelShaderGen.cpp | 9 ++++- .../Src/TextureConversionShader.cpp | 9 ++++- .../Core/VideoCommon/Src/VertexShaderGen.cpp | 9 ++++- .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 10 ++++- 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/Src/CommonFuncs.h b/Source/Core/Common/Src/CommonFuncs.h index 710c20955e..4321e6dba0 100644 --- a/Source/Core/Common/Src/CommonFuncs.h +++ b/Source/Core/Common/Src/CommonFuncs.h @@ -86,6 +86,45 @@ inline u64 _rotr64(u64 x, unsigned int shift){ #define unlink _unlink #define snprintf _snprintf #define vscprintf _vscprintf + +// Locale Cross-Compatibility + #define locale_t _locale_t + #define freelocale _free_locale + #define newlocale(mask, locale, base) _create_locale(mask, locale) + + #define LC_GLOBAL_LOCALE ((locale_t)-1) + #define LC_ALL_MASK LC_ALL + #define LC_COLLATE_MASK LC_COLLATE + #define LC_CTYPE_MASK LC_CTYPE + #define LC_MONETARY_MASK LC_MONETARY + #define LC_NUMERIC_MASK LC_NUMERIC + #define LC_TIME_MASK LC_TIME + + inline locale_t uselocale(locale_t new_locale) + { + // Retrieve the current per thread locale setting + bool bIsPerThread = (_configthreadlocale(0) == _ENABLE_PER_THREAD_LOCALE); + + // Retrieve the current thread-specific locale + locale_t old_locale = bIsPerThread ? _get_current_locale() : LC_GLOBAL_LOCALE; + + if(new_locale == LC_GLOBAL_LOCALE) + { + // Restore the global locale + _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); + } + else if(new_locale != NULL) + { + // Configure the thread to set the locale only for this thread + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + + // Set all locale categories + for(int i = LC_MIN; i <= LC_MAX; i++) + setlocale(i, new_locale->locinfo->lc_category[i].locale); + } + + return old_locale; + } // 64 bit offsets for windows #define fseeko _fseeki64 diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index e6a0512d7f..100cac5976 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -6,6 +6,9 @@ #include #include #include +#ifdef __APPLE__ + #include +#endif #include "LightingShaderGen.h" #include "PixelShaderGen.h" @@ -513,7 +516,8 @@ const char *WriteLocation(API_TYPE ApiType) const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) { - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation + locale_t old_locale = uselocale(locale); // Apply the locale for this thread text[sizeof(text) - 1] = 0x7C; // canary BuildSwapModeTable(); // Needed for WriteStage @@ -886,7 +890,8 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType if (text[sizeof(text) - 1] != 0x7C) PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); - setlocale(LC_NUMERIC, ""); // restore locale + uselocale(old_locale); // restore locale + freelocale(locale); return text; } diff --git a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp index 539d8799f9..573713a198 100644 --- a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp @@ -6,6 +6,9 @@ #include #include #include +#ifdef __APPLE__ + #include +#endif #include "TextureConversionShader.h" #include "TextureDecoder.h" @@ -804,7 +807,8 @@ void WriteZ24Encoder(char* p, API_TYPE ApiType) const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) { - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation + locale_t old_locale = uselocale(locale); // Apply the locale for this thread text[sizeof(text) - 1] = 0x7C; // canary char *p = text; @@ -888,7 +892,8 @@ const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) if (text[sizeof(text) - 1] != 0x7C) PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); - setlocale(LC_NUMERIC, ""); // restore locale + uselocale(old_locale); // restore locale + freelocale(locale); return text; } diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index f2f72251ef..aede4aa2bd 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -4,6 +4,9 @@ #include #include +#ifdef __APPLE__ + #include +#endif #include "NativeVertexFormat.h" @@ -173,7 +176,8 @@ extern const char *WriteLocation(API_TYPE ApiType); const char *GenerateVertexShaderCode(u32 components, API_TYPE ApiType) { - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation + locale_t old_locale = uselocale(locale); // Apply the locale for this thread text[sizeof(text) - 1] = 0x7C; // canary _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); @@ -640,6 +644,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE ApiType) if (text[sizeof(text) - 1] != 0x7C) PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); - setlocale(LC_NUMERIC, ""); // restore locale + uselocale(old_locale); // restore locale + freelocale(locale); return text; } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 37da0b7216..f46cf43bd2 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -4,6 +4,10 @@ #include #include +#include +#ifdef __APPLE__ + #include +#endif #include "Common.h" #include "Hash.h" @@ -155,7 +159,8 @@ static LPDIRECT3DPIXELSHADER9 CreateCopyShader(int copyMatrixType, int depthConv // this should create the same shaders as before (plus some extras added for DF16), just... more manageably than listing the full program for each combination char text[3072]; - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation + locale_t old_locale = uselocale(locale); // Apply the locale for this thread text[sizeof(text) - 1] = 0x7C; // canary char* p = text; @@ -215,7 +220,8 @@ static LPDIRECT3DPIXELSHADER9 CreateCopyShader(int copyMatrixType, int depthConv if (text[sizeof(text) - 1] != 0x7C) PanicAlert("PixelShaderCache copy shader generator - buffer too small, canary has been eaten!"); - setlocale(LC_NUMERIC, ""); // restore locale + uselocale(old_locale); // restore locale + freelocale(locale); return D3D::CompileAndCreatePixelShader(text, (int)strlen(text)); }