Remove aos::ComplexThreadLocal
We no longer need it with the built in language thread_local.
Signed-off-by: Tyler Chatow <tchatow@gmail.com>
Change-Id: I17c87139ee0121da9b66a80003570cfb618d39f4
diff --git a/aos/BUILD b/aos/BUILD
index 8a8a19a..025e78c 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -159,35 +159,6 @@
)
cc_library(
- name = "complex_thread_local",
- srcs = [
- "complex_thread_local.cc",
- ],
- hdrs = [
- "complex_thread_local.h",
- ],
- target_compatible_with = ["@platforms//os:linux"],
- visibility = ["//visibility:public"],
- deps = [
- "//aos:die",
- "@com_google_absl//absl/base",
- ],
-)
-
-cc_test(
- name = "complex_thread_local_test",
- srcs = [
- "complex_thread_local_test.cc",
- ],
- target_compatible_with = ["@platforms//os:linux"],
- deps = [
- ":complex_thread_local",
- "//aos/logging",
- "//aos/testing:googletest",
- ],
-)
-
-cc_library(
name = "init",
srcs = [
"init.cc",
diff --git a/aos/complex_thread_local.cc b/aos/complex_thread_local.cc
deleted file mode 100644
index 70f3e82..0000000
--- a/aos/complex_thread_local.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-#include "aos/complex_thread_local.h"
-
-#include <pthread.h>
-
-#include "aos/die.h"
-#include "absl/base/call_once.h"
-
-#define SIMPLE_CHECK(call) \
- do { \
- const int value = call; \
- if (value != 0) { \
- PRDie(value, "%s failed", #call); \
- } \
- } while (false)
-
-namespace aos {
-namespace {
-
-void ExecuteDestructorList(void *v) {
- for (const ComplexThreadLocalDestructor *c =
- static_cast<ComplexThreadLocalDestructor *>(v);
- c != nullptr; c = c->next) {
- c->function(c->param);
- }
-}
-
-void CreateKey(pthread_key_t **r) {
- static pthread_key_t hr;
- SIMPLE_CHECK(pthread_key_create(&hr, ExecuteDestructorList));
- *r = &hr;
-}
-
-absl::once_flag key_once;
-
-pthread_key_t *GetKey() {
- static pthread_key_t *key = nullptr;
- absl::call_once(key_once, CreateKey, &key);
- return key;
-}
-} // namespace
-
-void ComplexThreadLocalDestructor::Add() {
- static_assert(
- ::std::is_pod<ComplexThreadLocalDestructor>::value,
- "ComplexThreadLocalDestructor might not be safe to pass through void*");
- pthread_key_t *key = GetKey();
-
- next = static_cast<ComplexThreadLocalDestructor *>(pthread_getspecific(*key));
- SIMPLE_CHECK(pthread_setspecific(*key, this));
-}
-
-void ComplexThreadLocalDestructor::Remove() {
- pthread_key_t *key = GetKey();
-
- ComplexThreadLocalDestructor *previous = nullptr;
- for (ComplexThreadLocalDestructor *c =
- static_cast<ComplexThreadLocalDestructor *>(
- pthread_getspecific(*key));
- c != nullptr; c = c->next) {
- if (c == this) {
- // If it's the first one.
- if (previous == nullptr) {
- SIMPLE_CHECK(pthread_setspecific(*key, next));
- } else {
- previous->next = next;
- }
- return;
- }
- previous = c;
- }
- ::aos::Die("%p is not in the destructor list\n", this);
-}
-
-} // namespace aos
diff --git a/aos/complex_thread_local.h b/aos/complex_thread_local.h
deleted file mode 100644
index 5397f2f..0000000
--- a/aos/complex_thread_local.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef AOS_COMPLEX_THREAD_LOCAL_H_
-#define AOS_COMPLEX_THREAD_LOCAL_H_
-
-#include <cassert>
-#include <type_traits>
-#include <utility>
-
-namespace aos {
-
-// Instances form a (per-thread) list of destructor functions to call when the
-// thread exits.
-// Only ComplexThreadLocal should use this.
-struct ComplexThreadLocalDestructor {
- // Adds this to the list of destructors in this thread.
- void Add();
- // Removes this from the list of destructors in this thread. ::aos::Dies if it
- // is not there.
- void Remove();
-
- void (*function)(void *);
- void *param;
-
- ComplexThreadLocalDestructor *next;
-};
-
-// Handles creating a thread-local (per type) object with non-trivial
-// constructor and/or destructor. It will be correctly destroyed on thread exit.
-//
-// Each thread using an instantiation of this class has its own independent slot
-// for storing a T. An instance of T is not actually constructed until a thread
-// calls Create, after which a pointer to it will be returned from get() etc
-// until after Clear is called.
-//
-// Example usage:
-// class Something {
-// private:
-// class Data {
-// public:
-// Data(const ::std::string &value) : value_(value) {}
-//
-// int DoSomething() {
-// if (cached_result_ == 0) {
-// // Do something expensive with value_ and store it in
-// // cached_result_.
-// }
-// return cached_result_;
-// }
-//
-// private:
-// const ::std::string value_;
-// int cached_result_ = 0;
-// };
-// ComplexThreadLocal<Data> thread_local_;
-// ::std::string a_string_;
-//
-// int DoSomething() {
-// thread_local_.Create(a_string_);
-// return thread_local_->DoSomething();
-// }
-// };
-//
-// The current implementation is based on
-// <http://stackoverflow.com/questions/12049684/gcc-4-7-on-linux-pthreads-nontrivial-thread-local-workaround-using-thread-n>.
-// TODO(brians): Change this to just simple standard C++ thread_local once all
-// of our compilers have support.
-template <typename T>
-class ComplexThreadLocal {
- public:
- // Actually creates the object in this thread if there is not one there
- // already.
- // args are all perfectly forwarded to the constructor.
- template <typename... Args>
- void Create(Args &&...args) {
- if (initialized) return;
- new (&storage) T(::std::forward<Args>(args)...);
- destructor.function = PlacementDelete;
- destructor.param = &storage;
- destructor.Add();
- initialized = true;
- }
-
- // Removes the object in this thread (if any), including calling its
- // destructor.
- void Clear() {
- if (!initialized) return;
- destructor.Remove();
- PlacementDelete(&storage);
- initialized = false;
- }
-
- // Returns true if there is already an object in this thread.
- bool created() const { return initialized; }
-
- // Returns the object currently created in this thread or nullptr.
- T *operator->() const { return get(); }
- T *get() const {
- if (initialized) {
- return static_cast<T *>(static_cast<void *>(&storage));
- } else {
- return nullptr;
- }
- }
-
- private:
- typedef typename ::std::aligned_storage<
- sizeof(T), ::std::alignment_of<T>::value>::type Storage;
-
- // Convenient helper for calling a destructor.
- static void PlacementDelete(void *t) { static_cast<T *>(t)->~T(); }
-
- // True iff this storage has been initialized.
- static __thread bool initialized;
- // Where we actually store the object for this thread (if any).
- static __thread Storage storage;
- // The linked list element representing this storage.
- static __thread ComplexThreadLocalDestructor destructor;
-};
-
-template <typename T>
-__thread bool ComplexThreadLocal<T>::initialized;
-template <typename T>
-__thread typename ComplexThreadLocal<T>::Storage ComplexThreadLocal<T>::storage;
-template <typename T>
-__thread ComplexThreadLocalDestructor ComplexThreadLocal<T>::destructor;
-
-} // namespace aos
-
-#endif // AOS_COMPLEX_THREAD_LOCAL_H_
diff --git a/aos/complex_thread_local_test.cc b/aos/complex_thread_local_test.cc
deleted file mode 100644
index 5323dea..0000000
--- a/aos/complex_thread_local_test.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "aos/complex_thread_local.h"
-
-#include <atomic>
-#include <thread>
-
-#include "gtest/gtest.h"
-
-namespace aos {
-namespace testing {
-
-class ComplexThreadLocalTest : public ::testing::Test {
- protected:
- struct TraceableObject {
- TraceableObject(int data = 0) : data(data) { ++constructions; }
- ~TraceableObject() { ++destructions; }
-
- static ::std::atomic<int> constructions, destructions;
-
- int data;
- };
- ComplexThreadLocal<TraceableObject> local;
-
- private:
- void SetUp() override {
- local.Clear();
- EXPECT_EQ(TraceableObject::constructions, TraceableObject::destructions)
- << "There should be no way to create and destroy different numbers.";
- TraceableObject::constructions = TraceableObject::destructions = 0;
- }
-};
-::std::atomic<int> ComplexThreadLocalTest::TraceableObject::constructions;
-::std::atomic<int> ComplexThreadLocalTest::TraceableObject::destructions;
-
-TEST_F(ComplexThreadLocalTest, Basic) {
- EXPECT_EQ(0, TraceableObject::constructions);
- EXPECT_EQ(0, TraceableObject::destructions);
- EXPECT_FALSE(local.created());
- EXPECT_EQ(nullptr, local.get());
-
- local.Create(971);
- EXPECT_EQ(1, TraceableObject::constructions);
- EXPECT_EQ(0, TraceableObject::destructions);
- EXPECT_TRUE(local.created());
- EXPECT_EQ(971, local->data);
-
- local.Create(254);
- EXPECT_EQ(1, TraceableObject::constructions);
- EXPECT_EQ(0, TraceableObject::destructions);
- EXPECT_TRUE(local.created());
- EXPECT_EQ(971, local->data);
-
- local.Clear();
- EXPECT_EQ(1, TraceableObject::constructions);
- EXPECT_EQ(1, TraceableObject::destructions);
- EXPECT_FALSE(local.created());
- EXPECT_EQ(nullptr, local.get());
-
- local.Create(973);
- EXPECT_EQ(2, TraceableObject::constructions);
- EXPECT_EQ(1, TraceableObject::destructions);
- EXPECT_TRUE(local.created());
- EXPECT_EQ(973, local->data);
-}
-
-TEST_F(ComplexThreadLocalTest, AnotherThread) {
- EXPECT_FALSE(local.created());
- std::thread t1([this]() {
- EXPECT_FALSE(local.created());
- local.Create(971);
- EXPECT_TRUE(local.created());
- EXPECT_EQ(971, local->data);
- EXPECT_EQ(1, TraceableObject::constructions);
- EXPECT_EQ(0, TraceableObject::destructions);
- });
- t1.join();
- EXPECT_EQ(1, TraceableObject::constructions);
- EXPECT_EQ(1, TraceableObject::destructions);
- EXPECT_FALSE(local.created());
-}
-
-TEST_F(ComplexThreadLocalTest, TwoThreads) {
- std::thread thread([this]() {
- local.Create(971);
- EXPECT_EQ(971, local->data);
- EXPECT_EQ(0, TraceableObject::destructions);
- });
- local.Create(973);
- EXPECT_EQ(973, local->data);
- thread.join();
- EXPECT_TRUE(local.created());
- EXPECT_EQ(2, TraceableObject::constructions);
- EXPECT_EQ(1, TraceableObject::destructions);
- local.Clear();
- EXPECT_EQ(2, TraceableObject::constructions);
- EXPECT_EQ(2, TraceableObject::destructions);
- EXPECT_FALSE(local.created());
-}
-
-} // namespace testing
-} // namespace aos
diff --git a/aos/logging/BUILD b/aos/logging/BUILD
index 30fd0d1..10d41a3 100644
--- a/aos/logging/BUILD
+++ b/aos/logging/BUILD
@@ -20,7 +20,6 @@
deps = [
":printf_formats",
":sizes",
- "//aos:complex_thread_local",
"//aos:die",
"//aos:macros",
"//aos:thread_local",
diff --git a/aos/logging/context.cc b/aos/logging/context.cc
index 30d275b..9eaac50 100644
--- a/aos/logging/context.cc
+++ b/aos/logging/context.cc
@@ -18,7 +18,6 @@
extern char *program_invocation_name;
extern char *program_invocation_short_name;
-#include "aos/complex_thread_local.h"
#include "aos/die.h"
#include "aos/logging/implementations.h"
#include "aos/thread_local.h"
@@ -63,7 +62,7 @@
return process_name + '.' + thread_name;
}
-::aos::ComplexThreadLocal<Context> my_context;
+thread_local std::optional<Context> my_context;
// True if we're going to delete the current Context object ASAP. The
// reason for doing this instead of just deleting them is that tsan (at least)
@@ -77,7 +76,7 @@
// Used in aos/linux_code/init.cc when a thread's name is changed.
void ReloadThreadName() {
- if (my_context.created()) {
+ if (my_context.has_value()) {
my_context->ClearName();
}
}
@@ -99,21 +98,21 @@
Context *Context::Get() {
if (__builtin_expect(delete_current_context, false)) {
- my_context.Clear();
+ my_context.reset();
delete_current_context = false;
}
- if (__builtin_expect(!my_context.created(), false)) {
- my_context.Create();
+ if (__builtin_expect(!my_context.has_value(), false)) {
+ my_context.emplace();
my_context->ClearName();
my_context->source = getpid();
}
- return my_context.get();
+ return &*my_context;
}
void Context::Delete() { delete_current_context = true; }
void Context::DeleteNow() {
- my_context.Clear();
+ my_context.reset();
delete_current_context = false;
}