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();
23
  ~InstanceImpl() override;
24

            
25
  // ThreadLocal::Instance
26
  SlotPtr allocateSlot() override;
27
  void registerThread(Event::Dispatcher& dispatcher, bool main_thread) override;
28
  void shutdownGlobalThreading() override;
29
  void shutdownThread() override;
30
  Event::Dispatcher& dispatcher() override;
31
21
  bool isShutdown() const override { return shutdown_; }
32

            
33
private:
34
  // On destruction returns the slot index to the deferred delete queue (detaches it). This allows
35
  // a slot to be destructed on the main thread while controlling the lifetime of the underlying
36
  // slot as callbacks drain from workers.
37
  struct SlotImpl : public Slot {
38
    SlotImpl(InstanceImpl& parent, uint32_t index);
39
    ~SlotImpl() override;
40
    std::function<void()> wrapCallback(const std::function<void()>& cb);
41
    std::function<void()> dataCallback(const UpdateCb& cb);
42
    static bool currentThreadRegisteredWorker(uint32_t index);
43
    static ThreadLocalObjectSharedPtr getWorker(uint32_t index);
44

            
45
    // ThreadLocal::Slot
46
    ThreadLocalObjectSharedPtr get() override;
47
    void runOnAllThreads(const UpdateCb& cb) override;
48
    void runOnAllThreads(const UpdateCb& cb, const std::function<void()>& complete_cb) override;
49
    bool currentThreadRegistered() override;
50
    void set(InitializeCb cb) override;
51
340
    bool isShutdown() const override { return isShutdownImpl(); }
52
    // We need to call isShutdown inside the destructor, so it must be non-virtual.
53
111428
    bool isShutdownImpl() const { return parent_.shutdown_; }
54

            
55
    InstanceImpl& parent_;
56
    const uint32_t index_;
57
    // The following is used to safely verify via weak_ptr that this slot is still alive. This
58
    // does not prevent all races if a callback does not capture appropriately, but it does fix
59
    // the common case of a slot destroyed immediately before anything is posted to a worker.
60
    // NOTE: The general safety model of a slot is that it is destroyed immediately on the main
61
    //       thread. This means that *all* captures must not reference the slot object directly.
62
    //       this is why index_ is captured manually in callbacks that require it.
63
    // NOTE: When the slot is destroyed, the index is immediately recycled. This is safe because
64
    //       any new posts for a recycled index must come after any previous callbacks for the
65
    //       previous owner of the index.
66
    // TODO(mattklein123): Add clang-tidy analysis rule to check that "this" is not captured by
67
    // a TLS function call. This check will not prevent all bad captures, but it will at least
68
    // make the programmer more aware of potential issues.
69
    std::shared_ptr<bool> still_alive_guard_;
70
  };
71

            
72
  struct ThreadLocalData {
73
    Event::Dispatcher* dispatcher_{};
74
    std::vector<ThreadLocalObjectSharedPtr> data_;
75
  };
76

            
77
  void removeSlot(uint32_t slot);
78
  void runOnAllThreads(std::function<void()> cb);
79
  void runOnAllThreads(std::function<void()> cb, std::function<void()> main_callback);
80
  static void setThreadLocal(uint32_t index, ThreadLocalObjectSharedPtr object);
81

            
82
  static thread_local ThreadLocalData thread_local_data_;
83

            
84
  Thread::MainThread main_thread_;
85
  std::vector<Slot*> slots_;
86
  // A list of index of freed slots.
87
  std::list<uint32_t> free_slot_indexes_;
88
  std::list<std::reference_wrapper<Event::Dispatcher>> registered_threads_;
89
  Event::Dispatcher* main_thread_dispatcher_{};
90
  std::atomic<bool> shutdown_{};
91

            
92
  // Test only.
93
  friend class ThreadLocalInstanceImplTest;
94
};
95

            
96
using InstanceImplPtr = std::unique_ptr<InstanceImpl>;
97

            
98
} // namespace ThreadLocal
99
} // namespace Envoy