Improve SingletonThreadLocal performance
[folly.git] / folly / SingletonThreadLocal.h
index 943883b6f5931bfabff544fcb555534e7a6cfb39..3add4fefc3facce0a5c4a0fa6e66fe90e88f3a42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2016-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #pragma once
 
-#include <folly/ThreadLocal.h>
 #include <folly/Singleton.h>
+#include <folly/ThreadLocal.h>
 
 namespace folly {
 
+// SingletonThreadLocal
+//
+// This class can help you implement a per-thread leaky-singleton model within
+// your application. Please read the usage block at the top of Singleton.h as
+// the recommendations there are also generally applicable to this class.
+//
+// When we say this is "leaky" we mean that the T instances held by a
+// SingletonThreadLocal<T> will survive until their owning thread exits,
+// regardless of the lifetime of the singleton object holding them.  That
+// means that they can be safely used during process shutdown, and
+// that they can also be safely used in an application that spawns many
+// temporary threads throughout its life.
+//
+// Keywords to help people find this class in search:
+// Thread Local Singleton ThreadLocalSingleton
 template <typename T, typename Tag = detail::DefaultTag>
 class SingletonThreadLocal {
  public:
@@ -28,29 +43,29 @@ class SingletonThreadLocal {
 
   SingletonThreadLocal() : SingletonThreadLocal([]() { return new T(); }) {}
 
-  explicit SingletonThreadLocal(CreateFunc createFunc)
-      : singleton_([createFunc = std::move(createFunc)]() mutable {
-          return new ThreadLocalT([createFunc =
-                                       std::move(createFunc)]() mutable {
-            return new Wrapper(std::unique_ptr<T>(createFunc()));
+  template <typename Create>
+  FOLLY_NOINLINE explicit SingletonThreadLocal(Create create)
+      : singleton_([create = std::move(create)]() mutable {
+          return new ThreadLocalT([create = std::move(create)]() mutable {
+            return new Wrapper(std::unique_ptr<T>(create()));
           });
         }) {}
 
-  static T& get() {
+  FOLLY_ALWAYS_INLINE static T& get() {
 #ifdef FOLLY_TLS
-    if (UNLIKELY(*localPtr() == nullptr)) {
-      *localPtr() = &(**SingletonT::get());
-    }
-
-    return **localPtr();
+    return *localPtr() ? **localPtr() : *(*localPtr() = &getSlow());
 #else
     return **SingletonT::get();
 #endif
   }
 
  private:
+  FOLLY_NOINLINE static T& getSlow() {
+    return **SingletonT::get();
+  }
+
 #ifdef FOLLY_TLS
-  static T** localPtr() {
+  FOLLY_ALWAYS_INLINE static T** localPtr() {
     static FOLLY_TLS T* localPtr = nullptr;
     return &localPtr;
   }
@@ -77,4 +92,4 @@ class SingletonThreadLocal {
 
   SingletonT singleton_;
 };
-}
+} // namespace folly