Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
CrossVR committed Jun 16, 2013
1 parent 825c5ca commit fc7099a
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
39 changes: 39 additions & 0 deletions Source/Core/Common/Src/CommonFuncs.h
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/VideoCommon/Src/PixelShaderGen.cpp
Expand Up @@ -6,6 +6,9 @@
#include <cmath>
#include <assert.h>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif

#include "LightingShaderGen.h"
#include "PixelShaderGen.h"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 7 additions & 2 deletions Source/Core/VideoCommon/Src/TextureConversionShader.cpp
Expand Up @@ -6,6 +6,9 @@
#include <stdio.h>
#include <math.h>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif

#include "TextureConversionShader.h"
#include "TextureDecoder.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 7 additions & 2 deletions Source/Core/VideoCommon/Src/VertexShaderGen.cpp
Expand Up @@ -4,6 +4,9 @@

#include <math.h>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif

#include "NativeVertexFormat.h"

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
10 changes: 8 additions & 2 deletions Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp
Expand Up @@ -4,6 +4,10 @@

#include <map>
#include <set>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif

#include "Common.h"
#include "Hash.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}

Expand Down

0 comments on commit fc7099a

Please sign in to comment.