tls.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "tls.h"
  2. #include <util/generic/hash.h>
  3. #include <util/generic/intrlist.h>
  4. #include <util/generic/singleton.h>
  5. #include <util/generic/vector.h>
  6. #if defined(_unix_)
  7. #include <pthread.h>
  8. #endif
  9. using namespace NTls;
  10. namespace {
  11. static inline TAtomicBase AcquireKey() {
  12. static TAtomic cur;
  13. return AtomicIncrement(cur) - (TAtomicBase)1;
  14. }
  15. class TGenericTlsBase {
  16. public:
  17. using TSmallKey = size_t;
  18. class TPerThreadStorage {
  19. public:
  20. struct TKey: public TNonCopyable {
  21. inline TKey(TDtor dtor)
  22. : Key(AcquireKey())
  23. , Dtor(dtor)
  24. {
  25. }
  26. TSmallKey Key;
  27. TDtor Dtor;
  28. };
  29. class TStoredValue: public TIntrusiveListItem<TStoredValue> {
  30. public:
  31. inline TStoredValue(const TKey* key)
  32. : Data_(nullptr)
  33. , Dtor_(key->Dtor)
  34. {
  35. }
  36. inline ~TStoredValue() {
  37. if (Dtor_ && Data_) {
  38. Dtor_(Data_);
  39. }
  40. }
  41. inline void Set(void* ptr) noexcept {
  42. Data_ = ptr;
  43. }
  44. inline void* Get() const noexcept {
  45. return Data_;
  46. }
  47. private:
  48. void* Data_;
  49. TDtor Dtor_;
  50. };
  51. inline TStoredValue* Value(const TKey* key) {
  52. TStoredValue*& ret = *ValuePtr((size_t)key->Key);
  53. if (!ret) {
  54. THolder<TStoredValue> sv(new TStoredValue(key));
  55. Storage_.PushFront(sv.Get());
  56. ret = sv.Release();
  57. }
  58. return ret;
  59. }
  60. inline TStoredValue** ValuePtr(size_t idx) {
  61. // do not grow vector too much
  62. if (idx < 10000) {
  63. if (idx >= Values_.size()) {
  64. Values_.resize(idx + 1);
  65. }
  66. return &Values_[idx];
  67. }
  68. return &FarValues_[idx];
  69. }
  70. private:
  71. TVector<TStoredValue*> Values_;
  72. THashMap<size_t, TStoredValue*> FarValues_;
  73. TIntrusiveListWithAutoDelete<TStoredValue, TDelete> Storage_;
  74. };
  75. inline TPerThreadStorage* MyStorage() {
  76. #if defined(Y_HAVE_FAST_POD_TLS)
  77. Y_POD_STATIC_THREAD(TPerThreadStorage*)
  78. my(nullptr);
  79. if (!my) {
  80. my = MyStorageSlow();
  81. }
  82. return my;
  83. #else
  84. return MyStorageSlow();
  85. #endif
  86. }
  87. virtual TPerThreadStorage* MyStorageSlow() = 0;
  88. virtual ~TGenericTlsBase() = default;
  89. };
  90. }
  91. #if defined(_unix_)
  92. namespace {
  93. class TMasterTls: public TGenericTlsBase {
  94. public:
  95. inline TMasterTls() {
  96. Y_VERIFY(!pthread_key_create(&Key_, Dtor), "pthread_key_create failed");
  97. }
  98. inline ~TMasterTls() override {
  99. //explicitly call dtor for main thread
  100. Dtor(pthread_getspecific(Key_));
  101. Y_VERIFY(!pthread_key_delete(Key_), "pthread_key_delete failed");
  102. }
  103. static inline TMasterTls* Instance() {
  104. return SingletonWithPriority<TMasterTls, 1>();
  105. }
  106. private:
  107. TPerThreadStorage* MyStorageSlow() override {
  108. void* ret = pthread_getspecific(Key_);
  109. if (!ret) {
  110. ret = new TPerThreadStorage();
  111. Y_VERIFY(!pthread_setspecific(Key_, ret), "pthread_setspecific failed");
  112. }
  113. return (TPerThreadStorage*)ret;
  114. }
  115. static void Dtor(void* ptr) {
  116. delete (TPerThreadStorage*)ptr;
  117. }
  118. private:
  119. pthread_key_t Key_;
  120. };
  121. using TKeyDescriptor = TMasterTls::TPerThreadStorage::TKey;
  122. }
  123. class TKey::TImpl: public TKeyDescriptor {
  124. public:
  125. inline TImpl(TDtor dtor)
  126. : TKeyDescriptor(dtor)
  127. {
  128. }
  129. inline void* Get() const {
  130. return TMasterTls::Instance()->MyStorage()->Value(this)->Get();
  131. }
  132. inline void Set(void* val) const {
  133. TMasterTls::Instance()->MyStorage()->Value(this)->Set(val);
  134. }
  135. static inline void Cleanup() {
  136. }
  137. };
  138. #else
  139. namespace {
  140. class TGenericTls: public TGenericTlsBase {
  141. public:
  142. virtual TPerThreadStorage* MyStorageSlow() {
  143. auto lock = Guard(Lock_);
  144. {
  145. TPTSRef& ret = Datas_[TThread::CurrentThreadId()];
  146. if (!ret) {
  147. ret.Reset(new TPerThreadStorage());
  148. }
  149. return ret.Get();
  150. }
  151. }
  152. inline void Cleanup() noexcept {
  153. with_lock (Lock_) {
  154. Datas_.erase(TThread::CurrentThreadId());
  155. }
  156. }
  157. static inline TGenericTls* Instance() {
  158. return SingletonWithPriority<TGenericTls, 1>();
  159. }
  160. private:
  161. using TPTSRef = THolder<TPerThreadStorage>;
  162. TMutex Lock_;
  163. THashMap<TThread::TId, TPTSRef> Datas_;
  164. };
  165. }
  166. class TKey::TImpl {
  167. public:
  168. inline TImpl(TDtor dtor)
  169. : Key_(dtor)
  170. {
  171. }
  172. inline void* Get() {
  173. return TGenericTls::Instance()->MyStorage()->Value(&Key_)->Get();
  174. }
  175. inline void Set(void* ptr) {
  176. TGenericTls::Instance()->MyStorage()->Value(&Key_)->Set(ptr);
  177. }
  178. static inline void Cleanup() {
  179. TGenericTls::Instance()->Cleanup();
  180. }
  181. private:
  182. TGenericTls::TPerThreadStorage::TKey Key_;
  183. };
  184. #endif
  185. TKey::TKey(TDtor dtor)
  186. : Impl_(new TImpl(dtor))
  187. {
  188. }
  189. TKey::TKey(TKey&&) noexcept = default;
  190. TKey::~TKey() = default;
  191. void* TKey::Get() const {
  192. return Impl_->Get();
  193. }
  194. void TKey::Set(void* ptr) const {
  195. Impl_->Set(ptr);
  196. }
  197. void TKey::Cleanup() noexcept {
  198. TImpl::Cleanup();
  199. }