Work around a thread_local bug in MinGW with the WIN32 threading model

This commit is contained in:
mniip
2018-05-12 07:45:56 +03:00
parent 196371316d
commit 22e1de3fe8
2 changed files with 162 additions and 108 deletions

View File

@@ -2,7 +2,9 @@
#include <vector> #include <vector>
#include <locale> #include <locale>
#include <limits> #include <limits>
#include <stdexcept>
#include "common/tpt-thread.h"
#include "String.h" #include "String.h"
ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto) ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto)
@@ -294,7 +296,7 @@ char const numberChars[] = "-.+0123456789ABCDEFXabcdefx";
ByteString numberByteString(numberChars); ByteString numberByteString(numberChars);
String numberString(numberChars); String numberString(numberChars);
static thread_local struct LocaleImpl struct LocaleImpl
{ {
std::basic_stringstream<char> stream; std::basic_stringstream<char> stream;
std::basic_stringstream<wchar_t> wstream; std::basic_stringstream<wchar_t> wstream;
@@ -370,8 +372,34 @@ static thread_local struct LocaleImpl
{ {
wstream.str(std::basic_string<wchar_t>()); wstream.str(std::basic_string<wchar_t>());
} }
};
static void destroyLocaleImpl(void *ptr)
{
delete static_cast<LocaleImpl *>(ptr);
}
static pthread_once_t localeOnce = PTHREAD_ONCE_INIT;
static pthread_key_t localeKey;
static void createLocaleKey()
{
if(int error = pthread_key_create(&localeKey, destroyLocaleImpl))
throw std::system_error(error, std::system_category(), "Could not create TLS key for LocaleImpl");
}
static LocaleImpl *getLocaleImpl()
{
pthread_once(&localeOnce, createLocaleKey);
void *ptr = pthread_getspecific(localeKey);
if(!ptr)
{
ptr = static_cast<void *>(new LocaleImpl());
if(int error = pthread_setspecific(localeKey, ptr))
throw std::system_error(error, std::system_category(), "Could not put LocaleImpl into TLS");
}
return static_cast<LocaleImpl *>(ptr);
} }
LocaleImpl;
ByteString ByteStringBuilder::Build() const ByteString ByteStringBuilder::Build() const
{ {
@@ -386,65 +414,73 @@ void ByteStringBuilder::AddChars(ByteString::value_type const *data, size_t coun
ByteStringBuilder &operator<<(ByteStringBuilder &b, short int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, short int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, long int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, long int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, long long int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, long long int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned short int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned short int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long long int data) ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long long int data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
@@ -467,62 +503,67 @@ ByteStringBuilder &operator<<(ByteStringBuilder &b, ByteString const &data)
ByteStringBuilder &operator<<(ByteStringBuilder &b, float data) ByteStringBuilder &operator<<(ByteStringBuilder &b, float data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteStringBuilder &operator<<(ByteStringBuilder &b, double data) ByteStringBuilder &operator<<(ByteStringBuilder &b, double data)
{ {
LocaleImpl.PrepareStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream << data; impl->PrepareStream(b);
LocaleImpl.FlushStream(b); impl->stream << data;
impl->FlushStream(b);
return b; return b;
} }
ByteString::Split ByteString::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const ByteString::Split ByteString::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream >> value; impl->PrepareStream(*this, pos, set, reset);
if(LocaleImpl.stream.fail()) impl->stream >> value;
if(impl->stream.fail())
{ {
LocaleImpl.FlushStream(); impl->FlushStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.stream.clear(); impl->stream.clear();
Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); Split split(*this, pos, pos + impl->stream.tellg(), 0, false);
LocaleImpl.FlushStream(); impl->FlushStream();
return split; return split;
} }
ByteString::Split ByteString::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const ByteString::Split ByteString::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream >> value; impl->PrepareStream(*this, pos, set, reset);
if(LocaleImpl.stream.fail()) impl->stream >> value;
if(impl->stream.fail())
{ {
LocaleImpl.FlushStream(); impl->FlushStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.stream.clear(); impl->stream.clear();
Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); Split split(*this, pos, pos + impl->stream.tellg(), 0, false);
LocaleImpl.FlushStream(); impl->FlushStream();
return split; return split;
} }
ByteString::Split ByteString::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const ByteString::Split ByteString::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.stream >> value; impl->PrepareStream(*this, pos, set, reset);
if(LocaleImpl.stream.fail()) impl->stream >> value;
if(impl->stream.fail())
{ {
LocaleImpl.FlushStream(); impl->FlushStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.stream.clear(); impl->stream.clear();
Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); Split split(*this, pos, pos + impl->stream.tellg(), 0, false);
LocaleImpl.FlushStream(); impl->FlushStream();
return split; return split;
} }
@@ -539,65 +580,73 @@ void StringBuilder::AddChars(String::value_type const *data, size_t count)
StringBuilder &operator<<(StringBuilder &b, short int data) StringBuilder &operator<<(StringBuilder &b, short int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, int data) StringBuilder &operator<<(StringBuilder &b, int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, long int data) StringBuilder &operator<<(StringBuilder &b, long int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, long long int data) StringBuilder &operator<<(StringBuilder &b, long long int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, unsigned short int data) StringBuilder &operator<<(StringBuilder &b, unsigned short int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, unsigned int data) StringBuilder &operator<<(StringBuilder &b, unsigned int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, unsigned long int data) StringBuilder &operator<<(StringBuilder &b, unsigned long int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, unsigned long long int data) StringBuilder &operator<<(StringBuilder &b, unsigned long long int data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
@@ -627,61 +676,66 @@ StringBuilder &operator<<(StringBuilder &b, String const &data)
StringBuilder &operator<<(StringBuilder &b, float data) StringBuilder &operator<<(StringBuilder &b, float data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
StringBuilder &operator<<(StringBuilder &b, double data) StringBuilder &operator<<(StringBuilder &b, double data)
{ {
LocaleImpl.PrepareWStream(b); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream << data; impl->PrepareWStream(b);
LocaleImpl.FlushWStream(b); impl->wstream << data;
impl->FlushWStream(b);
return b; return b;
} }
String::Split String::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const String::Split String::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareWStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream >> value; impl->PrepareWStream(*this, pos, set, reset);
if(LocaleImpl.wstream.fail()) impl->wstream >> value;
if(impl->wstream.fail())
{ {
LocaleImpl.FlushWStream(); impl->FlushWStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.wstream.clear(); impl->wstream.clear();
Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); Split split(*this, pos, pos + impl->wstream.tellg(), 0, false);
LocaleImpl.FlushWStream(); impl->FlushWStream();
return split; return split;
} }
String::Split String::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const String::Split String::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareWStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream >> value; impl->PrepareWStream(*this, pos, set, reset);
if(LocaleImpl.wstream.fail()) impl->wstream >> value;
if(impl->wstream.fail())
{ {
LocaleImpl.FlushWStream(); impl->FlushWStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.wstream.clear(); impl->wstream.clear();
Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); Split split(*this, pos, pos + impl->wstream.tellg(), 0, false);
LocaleImpl.FlushWStream(); impl->FlushWStream();
return split; return split;
} }
String::Split String::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const String::Split String::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const
{ {
LocaleImpl.PrepareWStream(*this, pos, set, reset); LocaleImpl *impl = getLocaleImpl();
LocaleImpl.wstream >> value; impl->PrepareWStream(*this, pos, set, reset);
if(LocaleImpl.wstream.fail()) impl->wstream >> value;
if(impl->wstream.fail())
{ {
LocaleImpl.FlushWStream(); impl->FlushWStream();
return Split(*this, pos, npos, 0, false); return Split(*this, pos, npos, 0, false);
} }
LocaleImpl.wstream.clear(); impl->wstream.clear();
Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); Split split(*this, pos, pos + impl->wstream.tellg(), 0, false);
LocaleImpl.FlushWStream(); impl->FlushWStream();
return split; return split;
} }

View File

@@ -564,11 +564,11 @@ public:
template<typename T> ByteStringBuilder &operator<<(T) &&= delete; template<typename T> ByteStringBuilder &operator<<(T) &&= delete;
template<typename T, typename... Ts> ByteStringBuilder &Add(T &&arg, Ts&&... args) template<typename T, typename... Ts> inline ByteStringBuilder &Add(T &&arg, Ts&&... args)
{ {
return (*this << std::forward<T>(arg)).Add(std::forward<Ts>(args)...); return (*this << std::forward<T>(arg)).Add(std::forward<Ts>(args)...);
} }
ByteStringBuilder &Add() { return *this; } inline ByteStringBuilder &Add() { return *this; }
}; };
ByteStringBuilder &operator<<(ByteStringBuilder &, short int); ByteStringBuilder &operator<<(ByteStringBuilder &, short int);
@@ -607,11 +607,11 @@ public:
template<typename T> StringBuilder &operator<<(T) = delete; template<typename T> StringBuilder &operator<<(T) = delete;
template<typename T, typename... Ts> StringBuilder &Add(T &&arg, Ts&&... args) template<typename T, typename... Ts> inline StringBuilder &Add(T &&arg, Ts&&... args)
{ {
return (*this << std::forward<T>(arg)).Add(std::forward<Ts>(args)...); return (*this << std::forward<T>(arg)).Add(std::forward<Ts>(args)...);
} }
StringBuilder &Add() { return *this; } inline StringBuilder &Add() { return *this; }
}; };
StringBuilder &operator<<(StringBuilder &, short int); StringBuilder &operator<<(StringBuilder &, short int);