From a6848417fed706ec4f89a589c2ea9aa54eb39829 Mon Sep 17 00:00:00 2001 From: kulikov Date: Mon, 8 Jun 2026 20:33:12 +0300 Subject: Improve TGenericLocalValue, allow mixed thread-fiber-etc values Make generic local values more safe and usable: - instead of factory, register fiber/coroutine-aware "GLS (general local storage) contexts"; - put up to 4 (normally no more than 2 -- threads and one coroutine implementation) different "tls" variables into one generic, choose correct one from current execution context; - suitable version of variable will be constructed on demand (no dependency from first usage); - improve unit test too. commit_hash:8586846a6a775bd66dffcdf58263f78042be2480 --- library/cpp/threading/thread_local/generic.cpp | 65 ++++++++++++++++++++------ 1 file changed, 50 insertions(+), 15 deletions(-) (limited to 'library/cpp/threading/thread_local/generic.cpp') diff --git a/library/cpp/threading/thread_local/generic.cpp b/library/cpp/threading/thread_local/generic.cpp index 79161a846da..eca63d76bc6 100644 --- a/library/cpp/threading/thread_local/generic.cpp +++ b/library/cpp/threading/thread_local/generic.cpp @@ -14,29 +14,64 @@ namespace { NThreading::TThreadLocalValue Data_; }; - std::atomic& DefaultFactoryUsageCounter() { - static std::atomic v; - return v; - } + class TThreadLocalContext + : public NThreading::IGLSContext + { + bool IsCurrent() const override { + return true; + } - auto& genericLocalStorageFactory() { - static NThreading::TGenericLocalStorageFactory factory = [] { - DefaultFactoryUsageCounter() += 1; + THolder MakeStorage() const override { return MakeHolder(); - }; + } + }; + + class TContextRegistry { + public: + TContextRegistry() { + Register(MakeHolder()); + } + + size_t Count() const { + return Count_.load(); + } - return factory; + const NThreading::IGLSContext& Get(size_t index) const { + return *Contexts_[index]; + } + + void Register(THolder context) { + with_lock (Lock_) { + const size_t index = Count_.load(); + Y_ENSURE(index < NThreading::NDetail::MaxGLSContexts, "Too many generic local contexts registered"); + Contexts_[index] = std::move(context); + Count_.store(index + 1); + } + } + private: + TAdaptiveLock Lock_; + std::atomic Count_ = 0; + std::array, NThreading::NDetail::MaxGLSContexts> Contexts_ = {}; + }; + + TContextRegistry& Registry() { + static TContextRegistry registry; + return registry; } } namespace NThreading { - void SetGenericLocalStorageFactory(TGenericLocalStorageFactory factory) { - Y_ENSURE(DefaultFactoryUsageCounter() == 0, "There are some thread local values allocated with default factory"); - - genericLocalStorageFactory() = factory; + void RegisterGLSContext(THolder context) { + Registry().Register(std::move(context)); } - THolder MakeGenericLocalStorage() { - return genericLocalStorageFactory()(); + namespace NDetail { + size_t GLSContextCount() { + return Registry().Count(); + } + + const IGLSContext& GetGLSContext(size_t index) { + return Registry().Get(index); + } } } -- cgit v1.3