Line data Source code
1 : #pragma once 2 : 3 : #include <atomic> 4 : #include <cstdint> 5 : #include <list> 6 : #include <memory> 7 : #include <vector> 8 : 9 : #include "envoy/thread_local/thread_local.h" 10 : 11 : #include "source/common/common/logger.h" 12 : #include "source/common/common/non_copyable.h" 13 : 14 : namespace Envoy { 15 : namespace ThreadLocal { 16 : 17 : /** 18 : * Implementation of ThreadLocal that relies on static thread_local objects. 19 : */ 20 : class InstanceImpl : Logger::Loggable<Logger::Id::main>, public NonCopyable, public Instance { 21 : public: 22 : ~InstanceImpl() override; 23 : 24 : // ThreadLocal::Instance 25 : SlotPtr allocateSlot() override; 26 : void registerThread(Event::Dispatcher& dispatcher, bool main_thread) override; 27 : void shutdownGlobalThreading() override; 28 : void shutdownThread() override; 29 : Event::Dispatcher& dispatcher() override; 30 0 : bool isShutdown() const override { return shutdown_; } 31 : 32 : private: 33 : // On destruction returns the slot index to the deferred delete queue (detaches it). This allows 34 : // a slot to be destructed on the main thread while controlling the lifetime of the underlying 35 : // slot as callbacks drain from workers. 36 : struct SlotImpl : public Slot { 37 : SlotImpl(InstanceImpl& parent, uint32_t index); 38 1281 : ~SlotImpl() override { parent_.removeSlot(index_); } 39 : std::function<void()> wrapCallback(const std::function<void()>& cb); 40 : std::function<void()> dataCallback(const UpdateCb& cb); 41 : static bool currentThreadRegisteredWorker(uint32_t index); 42 : static ThreadLocalObjectSharedPtr getWorker(uint32_t index); 43 : 44 : // ThreadLocal::Slot 45 : ThreadLocalObjectSharedPtr get() override; 46 : void runOnAllThreads(const UpdateCb& cb) override; 47 : void runOnAllThreads(const UpdateCb& cb, const std::function<void()>& complete_cb) override; 48 : bool currentThreadRegistered() override; 49 : void set(InitializeCb cb) override; 50 0 : bool isShutdown() const override { return parent_.shutdown_; } 51 : 52 : InstanceImpl& parent_; 53 : const uint32_t index_; 54 : // The following is used to safely verify via weak_ptr that this slot is still alive. This 55 : // does not prevent all races if a callback does not capture appropriately, but it does fix 56 : // the common case of a slot destroyed immediately before anything is posted to a worker. 57 : // NOTE: The general safety model of a slot is that it is destroyed immediately on the main 58 : // thread. This means that *all* captures must not reference the slot object directly. 59 : // this is why index_ is captured manually in callbacks that require it. 60 : // NOTE: When the slot is destroyed, the index is immediately recycled. This is safe because 61 : // any new posts for a recycled index must come after any previous callbacks for the 62 : // previous owner of the index. 63 : // TODO(mattklein123): Add clang-tidy analysis rule to check that "this" is not captured by 64 : // a TLS function call. This check will not prevent all bad captures, but it will at least 65 : // make the programmer more aware of potential issues. 66 : std::shared_ptr<bool> still_alive_guard_; 67 : }; 68 : 69 : struct ThreadLocalData { 70 : Event::Dispatcher* dispatcher_{}; 71 : std::vector<ThreadLocalObjectSharedPtr> data_; 72 : }; 73 : 74 : void removeSlot(uint32_t slot); 75 : void runOnAllThreads(std::function<void()> cb); 76 : void runOnAllThreads(std::function<void()> cb, std::function<void()> main_callback); 77 : static void setThreadLocal(uint32_t index, ThreadLocalObjectSharedPtr object); 78 : 79 : static thread_local ThreadLocalData thread_local_data_; 80 : 81 : Thread::MainThread main_thread_; 82 : std::vector<Slot*> slots_; 83 : // A list of index of freed slots. 84 : std::list<uint32_t> free_slot_indexes_; 85 : std::list<std::reference_wrapper<Event::Dispatcher>> registered_threads_; 86 : Event::Dispatcher* main_thread_dispatcher_{}; 87 : std::atomic<bool> shutdown_{}; 88 : 89 : // Test only. 90 : friend class ThreadLocalInstanceImplTest; 91 : }; 92 : 93 : using InstanceImplPtr = std::unique_ptr<InstanceImpl>; 94 : 95 : } // namespace ThreadLocal 96 : } // namespace Envoy