Add a per-thread QuicConnectionContext for the upcoming QuicConnection tracing work.

PiperOrigin-RevId: 380237764
diff --git a/common/platform/api/quiche_thread_local.h b/common/platform/api/quiche_thread_local.h
new file mode 100644
index 0000000..c2d58e1
--- /dev/null
+++ b/common/platform/api/quiche_thread_local.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_THREAD_LOCAL_H_
+#define QUICHE_COMMON_PLATFORM_API_QUICHE_THREAD_LOCAL_H_
+
+#include "quiche_platform_impl/quiche_thread_local_impl.h"
+
+// Define a thread local |type*| with |name|. Conceptually, this is a
+//
+//  static thread_local type* name = nullptr;
+//
+// It is wrapped in a macro because the thread_local keyword is banned from
+// Chromium.
+#define DEFINE_QUICHE_THREAD_LOCAL_POINTER(name, type) \
+  DEFINE_QUICHE_THREAD_LOCAL_POINTER_IMPL(name, type)
+
+// Get the value of |name| for the current thread.
+#define GET_QUICHE_THREAD_LOCAL_POINTER(name) \
+  GET_QUICHE_THREAD_LOCAL_POINTER_IMPL(name)
+
+// Set the |value| of |name| for the current thread.
+#define SET_QUICHE_THREAD_LOCAL_POINTER(name, value) \
+  SET_QUICHE_THREAD_LOCAL_POINTER_IMPL(name, value)
+
+#endif  // QUICHE_COMMON_PLATFORM_API_QUICHE_THREAD_LOCAL_H_
diff --git a/common/platform/default/quiche_platform_impl/quiche_thread_local_impl.h b/common/platform/default/quiche_platform_impl/quiche_thread_local_impl.h
new file mode 100644
index 0000000..5ebea4c
--- /dev/null
+++ b/common/platform/default/quiche_platform_impl/quiche_thread_local_impl.h
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_THREAD_LOCAL_IMPL_H_
+#define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_THREAD_LOCAL_IMPL_H_
+
+#define DEFINE_QUICHE_THREAD_LOCAL_POINTER_IMPL(name, type) \
+  struct QuicheThreadLocalPointer_##name {                  \
+    static type** Instance() {                              \
+      static thread_local type* instance = nullptr;         \
+      return &instance;                                     \
+    }                                                       \
+    static type* Get() { return *Instance(); }              \
+    static void Set(type* ptr) { *Instance() = ptr; }       \
+  }
+
+#define GET_QUICHE_THREAD_LOCAL_POINTER_IMPL(name) \
+  QuicheThreadLocalPointer_##name::Get()
+
+#define SET_QUICHE_THREAD_LOCAL_POINTER_IMPL(name, value) \
+  QuicheThreadLocalPointer_##name::Set(value)
+
+#endif  // QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_THREAD_LOCAL_IMPL_H_
diff --git a/quic/core/quic_connection_context.cc b/quic/core/quic_connection_context.cc
new file mode 100644
index 0000000..65a8dd6
--- /dev/null
+++ b/quic/core/quic_connection_context.cc
@@ -0,0 +1,29 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/quic_connection_context.h"
+
+#include "common/platform/api/quiche_thread_local.h"
+
+namespace quic {
+namespace {
+DEFINE_QUICHE_THREAD_LOCAL_POINTER(CurrentContext, QuicConnectionContext);
+}  // namespace
+
+// static
+QuicConnectionContext* QuicConnectionContext::Current() {
+  return GET_QUICHE_THREAD_LOCAL_POINTER(CurrentContext);
+}
+
+QuicConnectionContextSwitcher::QuicConnectionContextSwitcher(
+    QuicConnectionContext* new_context)
+    : old_context_(QuicConnectionContext::Current()) {
+  SET_QUICHE_THREAD_LOCAL_POINTER(CurrentContext, new_context);
+}
+
+QuicConnectionContextSwitcher::~QuicConnectionContextSwitcher() {
+  SET_QUICHE_THREAD_LOCAL_POINTER(CurrentContext, old_context_);
+}
+
+}  // namespace quic
diff --git a/quic/core/quic_connection_context.h b/quic/core/quic_connection_context.h
new file mode 100644
index 0000000..05b09cf
--- /dev/null
+++ b/quic/core/quic_connection_context.h
@@ -0,0 +1,101 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_CONNECTION_CONTEXT_H_
+#define QUICHE_QUIC_CORE_QUIC_CONNECTION_CONTEXT_H_
+
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "quic/platform/api/quic_export.h"
+#include "common/platform/api/quiche_logging.h"
+
+namespace quic {
+
+// QuicConnectionTracer is responsible for emit trace messages for a single
+// QuicConnection.
+// QuicConnectionTracer is part of the QuicConnectionContext.
+class QUIC_EXPORT_PRIVATE QuicConnectionTracer {
+ public:
+  virtual ~QuicConnectionTracer() = default;
+
+  // Emit a trace message from a string literal. The trace may simply remember
+  // the address of the literal in this function and read it at a later time.
+  virtual void PrintLiteral(const char* literal) = 0;
+
+  // Emit a trace message from a string_view. Unlike PrintLiteral, this function
+  // will not read |s| after it returns.
+  virtual void PrintString(absl::string_view s) = 0;
+
+  // Emit a trace message from printf-style arguments.
+  template <typename... Args>
+  void Printf(const absl::FormatSpec<Args...>& format, const Args&... args) {
+    std::string s = absl::StrFormat(format, args...);
+    PrintString(s);
+  }
+};
+
+// QuicConnectionContext is a per-QuicConnection context that includes
+// facilities useable by any part of a QuicConnection. A QuicConnectionContext
+// is owned by a QuicConnection.
+//
+// The 'top-level' QuicConnection functions are responsible for maintaining the
+// thread-local QuicConnectionContext pointer, such that any function called by
+// them(directly or indirectly) can access the context.
+//
+// Like QuicConnection, all facilities in QuicConnectionContext are assumed to
+// be called from a single thread at a time, they are NOT thread-safe.
+struct QUIC_EXPORT_PRIVATE QuicConnectionContext final {
+  // Get the context on the current executing thread. nullptr if the current
+  // function is not called from a 'top-level' QuicConnection function.
+  static QuicConnectionContext* Current();
+
+  std::unique_ptr<QuicConnectionTracer> tracer;
+};
+
+// QuicConnectionContextSwitcher is a RAII object used for maintaining the
+// thread-local QuicConnectionContext pointer.
+class QUIC_EXPORT_PRIVATE QuicConnectionContextSwitcher final {
+ public:
+  // The constructor switches from QuicConnectionContext::Current() to
+  // |new_context|.
+  explicit QuicConnectionContextSwitcher(QuicConnectionContext* new_context);
+
+  // The destructor switches from QuicConnectionContext::Current() back to the
+  // old context.
+  ~QuicConnectionContextSwitcher();
+
+ private:
+  QuicConnectionContext* old_context_;
+};
+
+// Emit a trace message from a string literal to the current tracer(if any).
+inline void QUIC_TRACELITERAL(const char* literal) {
+  QuicConnectionContext* current = QuicConnectionContext::Current();
+  if (current && current->tracer) {
+    current->tracer->PrintLiteral(literal);
+  }
+}
+
+// Emit a trace message from a string_view to the current tracer(if any).
+inline void QUIC_TRACESTRING(absl::string_view s) {
+  QuicConnectionContext* current = QuicConnectionContext::Current();
+  if (current && current->tracer) {
+    current->tracer->PrintString(s);
+  }
+}
+
+// Emit a trace message from printf-style arguments to the current tracer(if
+// any).
+template <typename... Args>
+void QUIC_TRACEPRINTF(const absl::FormatSpec<Args...>& format,
+                      const Args&... args) {
+  QuicConnectionContext* current = QuicConnectionContext::Current();
+  if (current && current->tracer) {
+    current->tracer->Printf(format, args...);
+  }
+}
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_QUIC_CONNECTION_CONTEXT_H_
diff --git a/quic/core/quic_connection_context_test.cc b/quic/core/quic_connection_context_test.cc
new file mode 100644
index 0000000..0f5b2c4
--- /dev/null
+++ b/quic/core/quic_connection_context_test.cc
@@ -0,0 +1,173 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/quic_connection_context.h"
+
+#include "quic/platform/api/quic_test.h"
+#include "quic/platform/api/quic_thread.h"
+
+using testing::ElementsAre;
+
+namespace quic {
+namespace {
+
+class TraceCollector : public QuicConnectionTracer {
+ public:
+  ~TraceCollector() override = default;
+
+  void PrintLiteral(const char* literal) override { trace_.push_back(literal); }
+
+  void PrintString(absl::string_view s) override {
+    trace_.push_back(std::string(s));
+  }
+
+  const std::vector<std::string>& trace() const { return trace_; }
+
+ private:
+  std::vector<std::string> trace_;
+};
+
+struct FakeConnection {
+  FakeConnection() { context.tracer = std::make_unique<TraceCollector>(); }
+
+  const std::vector<std::string>& trace() const {
+    return static_cast<const TraceCollector*>(context.tracer.get())->trace();
+  }
+
+  QuicConnectionContext context;
+};
+
+void SimpleSwitch() {
+  FakeConnection connection;
+
+  // These should be ignored since current context is nullptr.
+  EXPECT_EQ(QuicConnectionContext::Current(), nullptr);
+  QUIC_TRACELITERAL("before switch: literal");
+  QUIC_TRACESTRING(std::string("before switch: string"));
+  QUIC_TRACEPRINTF("%s: %s", "before switch", "printf");
+
+  {
+    QuicConnectionContextSwitcher switcher(&connection.context);
+    QUIC_TRACELITERAL("literal");
+    QUIC_TRACESTRING(std::string("string"));
+    QUIC_TRACEPRINTF("%s", "printf");
+  }
+
+  EXPECT_EQ(QuicConnectionContext::Current(), nullptr);
+  QUIC_TRACELITERAL("after switch: literal");
+  QUIC_TRACESTRING(std::string("after switch: string"));
+  QUIC_TRACEPRINTF("%s: %s", "after switch", "printf");
+
+  EXPECT_THAT(connection.trace(), ElementsAre("literal", "string", "printf"));
+}
+
+void NestedSwitch() {
+  FakeConnection outer, inner;
+
+  {
+    QuicConnectionContextSwitcher switcher(&outer.context);
+    QUIC_TRACELITERAL("outer literal 0");
+    QUIC_TRACESTRING(std::string("outer string 0"));
+    QUIC_TRACEPRINTF("%s %s %d", "outer", "printf", 0);
+
+    {
+      QuicConnectionContextSwitcher switcher(&inner.context);
+      QUIC_TRACELITERAL("inner literal");
+      QUIC_TRACESTRING(std::string("inner string"));
+      QUIC_TRACEPRINTF("%s %s", "inner", "printf");
+    }
+
+    QUIC_TRACELITERAL("outer literal 1");
+    QUIC_TRACESTRING(std::string("outer string 1"));
+    QUIC_TRACEPRINTF("%s %s %d", "outer", "printf", 1);
+  }
+
+  EXPECT_THAT(outer.trace(), ElementsAre("outer literal 0", "outer string 0",
+                                         "outer printf 0", "outer literal 1",
+                                         "outer string 1", "outer printf 1"));
+
+  EXPECT_THAT(inner.trace(),
+              ElementsAre("inner literal", "inner string", "inner printf"));
+}
+
+void AlternatingSwitch() {
+  FakeConnection zero, one, two;
+  for (int i = 0; i < 15; ++i) {
+    FakeConnection* connection =
+        ((i % 3) == 0) ? &zero : (((i % 3) == 1) ? &one : &two);
+
+    QuicConnectionContextSwitcher switcher(&connection->context);
+    QUIC_TRACEPRINTF("%d", i);
+  }
+
+  EXPECT_THAT(zero.trace(), ElementsAre("0", "3", "6", "9", "12"));
+  EXPECT_THAT(one.trace(), ElementsAre("1", "4", "7", "10", "13"));
+  EXPECT_THAT(two.trace(), ElementsAre("2", "5", "8", "11", "14"));
+}
+
+typedef void (*ThreadFunction)();
+
+template <ThreadFunction func>
+class TestThread : public QuicThread {
+ public:
+  TestThread() : QuicThread("TestThread") {}
+  ~TestThread() override = default;
+
+ protected:
+  void Run() override { func(); }
+};
+
+template <ThreadFunction func>
+void RunInThreads(size_t n_threads) {
+  using ThreadType = TestThread<func>;
+  std::vector<ThreadType> threads(n_threads);
+
+  for (ThreadType& t : threads) {
+    t.Start();
+  }
+
+  for (ThreadType& t : threads) {
+    t.Join();
+  }
+}
+
+class QuicConnectionContextTest : public QuicTest {
+ protected:
+};
+
+TEST_F(QuicConnectionContextTest, NullTracerOK) {
+  FakeConnection connection;
+  std::unique_ptr<QuicConnectionTracer> tracer;
+
+  {
+    QuicConnectionContextSwitcher switcher(&connection.context);
+    QUIC_TRACELITERAL("msg 1 recorded");
+  }
+
+  connection.context.tracer.swap(tracer);
+
+  {
+    QuicConnectionContextSwitcher switcher(&connection.context);
+    // Should be a no-op since connection.context.tracer is nullptr.
+    QUIC_TRACELITERAL("msg 2 ignored");
+  }
+
+  EXPECT_THAT(static_cast<TraceCollector*>(tracer.get())->trace(),
+              ElementsAre("msg 1 recorded"));
+}
+
+TEST_F(QuicConnectionContextTest, TestSimpleSwitch) {
+  RunInThreads<SimpleSwitch>(10);
+}
+
+TEST_F(QuicConnectionContextTest, TestNestedSwitch) {
+  RunInThreads<NestedSwitch>(10);
+}
+
+TEST_F(QuicConnectionContextTest, TestAlternatingSwitch) {
+  RunInThreads<AlternatingSwitch>(10);
+}
+
+}  // namespace
+}  // namespace quic