Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/thread_local/thread_local_impl.h
Line
Count
Source (jump to first uncovered line)
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
2.64k
  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
48.0k
    ~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