Allow optional atfork hook for singleton destruction
authorAndrii Grynenko <andrii@fb.com>
Thu, 5 May 2016 23:41:33 +0000 (16:41 -0700)
committerFacebook Github Bot 3 <facebook-github-bot-3-bot@fb.com>
Thu, 5 May 2016 23:50:36 +0000 (16:50 -0700)
Summary: Grouping all folly::ThreadLocal atfork hooks in one. This allows proper ordering between folly::ThreadLocal hooks and hooks added by other libraries (we always want folly::ThreadLocal hooks to be registered first).

Reviewed By: ericniebler

Differential Revision: D3262666

fb-gh-sync-id: 1aa928b9ddd484580f4a4a7b320e9e64164bb04a
fbshipit-source-id: 1aa928b9ddd484580f4a4a7b320e9e64164bb04a

folly/detail/ThreadLocalDetail.cpp
folly/detail/ThreadLocalDetail.h

index 4a8f2b66d2db0767785d1cbb10aa0cc871ea0430..7dcb22d4ccc0a44b00f352dae5dddfb46eb820d4 100644 (file)
@@ -15,6 +15,9 @@
  */
 #include <folly/ThreadLocal.h>
 
+#include <list>
+#include <mutex>
+
 namespace folly { namespace threadlocal_detail {
 
 StaticMetaBase::StaticMetaBase(ThreadEntry* (*threadEntry)())
@@ -222,6 +225,79 @@ void StaticMetaBase::reserve(EntryID* id) {
   free(reallocated);
 }
 
+namespace {
+
+struct AtForkTask {
+  folly::Function<void()> prepare;
+  folly::Function<void()> parent;
+  folly::Function<void()> child;
+};
+
+class AtForkList {
+ public:
+  static AtForkList& instance() {
+    static auto instance = new AtForkList();
+    return *instance;
+  }
+
+  static void prepare() noexcept {
+    instance().tasksLock.lock();
+    auto& tasks = instance().tasks;
+    for (auto task = tasks.rbegin(); task != tasks.rend(); ++task) {
+      task->prepare();
+    }
+  }
+
+  static void parent() noexcept {
+    auto& tasks = instance().tasks;
+    for (auto& task : tasks) {
+      task.parent();
+    }
+    instance().tasksLock.unlock();
+  }
+
+  static void child() noexcept {
+    auto& tasks = instance().tasks;
+    for (auto& task : tasks) {
+      task.child();
+    }
+    instance().tasksLock.unlock();
+  }
+
+  std::mutex tasksLock;
+  std::list<AtForkTask> tasks;
+
+ private:
+  AtForkList() {
+#if FOLLY_HAVE_PTHREAD_ATFORK
+    int ret = pthread_atfork(
+        &AtForkList::prepare, &AtForkList::parent, &AtForkList::child);
+    checkPosixError(ret, "pthread_atfork failed");
+#elif !__ANDROID__ && !defined(_MSC_VER)
+// pthread_atfork is not part of the Android NDK at least as of n9d. If
+// something is trying to call native fork() directly at all with Android's
+// process management model, this is probably the least of the problems.
+//
+// But otherwise, this is a problem.
+#warning pthread_atfork unavailable
+#endif
+  }
+};
+}
+
+void StaticMetaBase::initAtFork() {
+  AtForkList::instance();
+}
+
+void StaticMetaBase::registerAtFork(
+    folly::Function<void()> prepare,
+    folly::Function<void()> parent,
+    folly::Function<void()> child) {
+  std::lock_guard<std::mutex> lg(AtForkList::instance().tasksLock);
+  AtForkList::instance().tasks.push_back(
+      {std::move(prepare), std::move(parent), std::move(child)});
+}
+
 FOLLY_STATIC_CTOR_PRIORITY_MAX
 PthreadKeyUnregister PthreadKeyUnregister::instance_;
 }}
index 65ecfc672416528e7a0942e8b76a4c21637f74dc..29e06b1f3bf1cc73a339656ae1608f69f26ed127 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <folly/Exception.h>
 #include <folly/Foreach.h>
+#include <folly/Function.h>
 #include <folly/Malloc.h>
 #include <folly/MicroSpinLock.h>
 #include <folly/Portability.h>
@@ -272,6 +273,12 @@ struct StaticMetaBase {
 
   ElementWrapper& get(EntryID* ent);
 
+  static void initAtFork();
+  static void registerAtFork(
+      folly::Function<void()> prepare,
+      folly::Function<void()> parent,
+      folly::Function<void()> child);
+
   uint32_t nextId_;
   std::vector<uint32_t> freeIds_;
   std::mutex lock_;
@@ -290,20 +297,10 @@ struct StaticMetaBase {
 template <class Tag>
 struct StaticMeta : StaticMetaBase {
   StaticMeta() : StaticMetaBase(&StaticMeta::getThreadEntrySlow) {
-#if FOLLY_HAVE_PTHREAD_ATFORK
-    int ret = pthread_atfork(
+    registerAtFork(
         /*prepare*/ &StaticMeta::preFork,
         /*parent*/ &StaticMeta::onForkParent,
         /*child*/ &StaticMeta::onForkChild);
-    checkPosixError(ret, "pthread_atfork failed");
-#elif !__ANDROID__ && !defined(_MSC_VER)
-    // pthread_atfork is not part of the Android NDK at least as of n9d. If
-    // something is trying to call native fork() directly at all with Android's
-    // process management model, this is probably the least of the problems.
-    //
-    // But otherwise, this is a problem.
-    #warning pthread_atfork unavailable
-#endif
   }
 
   static StaticMeta<Tag>& instance() {