From 246476883ac62679b92a7ff0a3792fa4de97cb76 Mon Sep 17 00:00:00 2001 From: mniip Date: Sun, 13 May 2018 02:33:37 +0300 Subject: [PATCH] Scrap thread_local entirely. Implement our own with pthread_key --- src/common/String.cpp | 271 ++++++++++++++++++++++++------------------ src/common/String.h | 8 +- 2 files changed, 162 insertions(+), 117 deletions(-) diff --git a/src/common/String.cpp b/src/common/String.cpp index 735ca1fd06..df56d5ec8b 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -2,7 +2,9 @@ #include #include #include +#include +#include "common/tpt-thread.h" #include "String.h" ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto) @@ -294,7 +296,7 @@ char const numberChars[] = "-.+0123456789ABCDEFXabcdefx"; ByteString numberByteString(numberChars); String numberString(numberChars); -static thread_local struct LocaleImpl +struct LocaleImpl { std::basic_stringstream stream; std::basic_stringstream wstream; @@ -305,15 +307,6 @@ static thread_local struct LocaleImpl wstream.imbue(std::locale::classic()); } -#if defined(WIN) && defined(__GNUC__) && !defined(_64BIT) - // The MinGW WIN32 threading model is currently broken in that the - // runtime invokes the destructors via cdecl, while the compiled code - // expects thiscall. - __cdecl ~LocaleImpl() - { - } -#endif - inline void PrepareStream(ByteStringBuilder &b) { stream.flags(b.flags); @@ -379,8 +372,34 @@ static thread_local struct LocaleImpl { wstream.str(std::basic_string()); } +}; + +static void destroyLocaleImpl(void *ptr) +{ + delete static_cast(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(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(ptr); } -LocaleImpl; ByteString ByteStringBuilder::Build() const { @@ -395,65 +414,73 @@ void ByteStringBuilder::AddChars(ByteString::value_type const *data, size_t coun ByteStringBuilder &operator<<(ByteStringBuilder &b, short int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, long int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, long long int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned short int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long long int data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } @@ -476,62 +503,67 @@ ByteStringBuilder &operator<<(ByteStringBuilder &b, ByteString const &data) ByteStringBuilder &operator<<(ByteStringBuilder &b, float data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(b); return b; } ByteStringBuilder &operator<<(ByteStringBuilder &b, double data) { - LocaleImpl.PrepareStream(b); - LocaleImpl.stream << data; - LocaleImpl.FlushStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(b); + impl->stream << data; + impl->FlushStream(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 { - LocaleImpl.PrepareStream(*this, pos, set, reset); - LocaleImpl.stream >> value; - if(LocaleImpl.stream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(*this, pos, set, reset); + impl->stream >> value; + if(impl->stream.fail()) { - LocaleImpl.FlushStream(); + impl->FlushStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.stream.clear(); - Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); - LocaleImpl.FlushStream(); + impl->stream.clear(); + Split split(*this, pos, pos + impl->stream.tellg(), 0, false); + impl->FlushStream(); 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 { - LocaleImpl.PrepareStream(*this, pos, set, reset); - LocaleImpl.stream >> value; - if(LocaleImpl.stream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(*this, pos, set, reset); + impl->stream >> value; + if(impl->stream.fail()) { - LocaleImpl.FlushStream(); + impl->FlushStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.stream.clear(); - Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); - LocaleImpl.FlushStream(); + impl->stream.clear(); + Split split(*this, pos, pos + impl->stream.tellg(), 0, false); + impl->FlushStream(); return split; } 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.stream >> value; - if(LocaleImpl.stream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareStream(*this, pos, set, reset); + impl->stream >> value; + if(impl->stream.fail()) { - LocaleImpl.FlushStream(); + impl->FlushStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.stream.clear(); - Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); - LocaleImpl.FlushStream(); + impl->stream.clear(); + Split split(*this, pos, pos + impl->stream.tellg(), 0, false); + impl->FlushStream(); return split; } @@ -548,65 +580,73 @@ void StringBuilder::AddChars(String::value_type const *data, size_t count) StringBuilder &operator<<(StringBuilder &b, short int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, long int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, long long int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, unsigned short int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, unsigned int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, unsigned long int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, unsigned long long int data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } @@ -636,61 +676,66 @@ StringBuilder &operator<<(StringBuilder &b, String const &data) StringBuilder &operator<<(StringBuilder &b, float data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(b); return b; } StringBuilder &operator<<(StringBuilder &b, double data) { - LocaleImpl.PrepareWStream(b); - LocaleImpl.wstream << data; - LocaleImpl.FlushWStream(b); + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(b); + impl->wstream << data; + impl->FlushWStream(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 { - LocaleImpl.PrepareWStream(*this, pos, set, reset); - LocaleImpl.wstream >> value; - if(LocaleImpl.wstream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(*this, pos, set, reset); + impl->wstream >> value; + if(impl->wstream.fail()) { - LocaleImpl.FlushWStream(); + impl->FlushWStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.wstream.clear(); - Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); - LocaleImpl.FlushWStream(); + impl->wstream.clear(); + Split split(*this, pos, pos + impl->wstream.tellg(), 0, false); + impl->FlushWStream(); 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 { - LocaleImpl.PrepareWStream(*this, pos, set, reset); - LocaleImpl.wstream >> value; - if(LocaleImpl.wstream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(*this, pos, set, reset); + impl->wstream >> value; + if(impl->wstream.fail()) { - LocaleImpl.FlushWStream(); + impl->FlushWStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.wstream.clear(); - Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); - LocaleImpl.FlushWStream(); + impl->wstream.clear(); + Split split(*this, pos, pos + impl->wstream.tellg(), 0, false); + impl->FlushWStream(); return split; } 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.wstream >> value; - if(LocaleImpl.wstream.fail()) + LocaleImpl *impl = getLocaleImpl(); + impl->PrepareWStream(*this, pos, set, reset); + impl->wstream >> value; + if(impl->wstream.fail()) { - LocaleImpl.FlushWStream(); + impl->FlushWStream(); return Split(*this, pos, npos, 0, false); } - LocaleImpl.wstream.clear(); - Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); - LocaleImpl.FlushWStream(); + impl->wstream.clear(); + Split split(*this, pos, pos + impl->wstream.tellg(), 0, false); + impl->FlushWStream(); return split; } diff --git a/src/common/String.h b/src/common/String.h index 57a06f1d46..ea024be01c 100644 --- a/src/common/String.h +++ b/src/common/String.h @@ -564,11 +564,11 @@ class ByteStringBuilder template ByteStringBuilder &operator<<(T) &&= delete; - template ByteStringBuilder &Add(T &&arg, Ts&&... args) + template inline ByteStringBuilder &Add(T &&arg, Ts&&... args) { return (*this << std::forward(arg)).Add(std::forward(args)...); } - ByteStringBuilder &Add() { return *this; } + inline ByteStringBuilder &Add() { return *this; } }; ByteStringBuilder &operator<<(ByteStringBuilder &, short int); @@ -607,11 +607,11 @@ class StringBuilder template StringBuilder &operator<<(T) = delete; - template StringBuilder &Add(T &&arg, Ts&&... args) + template inline StringBuilder &Add(T &&arg, Ts&&... args) { return (*this << std::forward(arg)).Add(std::forward(args)...); } - StringBuilder &Add() { return *this; } + inline StringBuilder &Add() { return *this; } }; StringBuilder &operator<<(StringBuilder &, short int);