From b51f8cd7431aa84f97cfb6515219b57ed6da2efe Mon Sep 17 00:00:00 2001 From: Akshay Vaidya Date: Fri, 9 May 2014 10:07:05 -0700 Subject: [PATCH] Adding a release function for ThreadLocalPtr. Summary: ThreadLocalPtr manages the lifecycle of the object that is stored with it. We have a use case where we sometimes want to transfer ownership of the stored object to another thread by wrapping them with unique_ptrs. Adding a release function, similar to to the unique_ptr::release is the cleanest way for us to transfer ownership. Test Plan: I can do some on off testing using a command line tool, but I was wondering about how to add some unit tests. Not sure when the folly unit tests were. Reviewed By: njormrod@fb.com FB internal diff: D1321588 --- folly/ThreadLocal.h | 7 +++++++ folly/detail/ThreadLocalDetail.h | 27 +++++++++++++++++++++------ folly/test/ThreadLocalTest.cpp | 15 +++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/folly/ThreadLocal.h b/folly/ThreadLocal.h index bae58411..05d26bfb 100644 --- a/folly/ThreadLocal.h +++ b/folly/ThreadLocal.h @@ -165,6 +165,13 @@ class ThreadLocalPtr { return *get(); } + T* release() { + threadlocal_detail::ElementWrapper& w = + threadlocal_detail::StaticMeta::get(id_); + + return static_cast(w.release()); + } + void reset(T* newPtr = nullptr) { threadlocal_detail::ElementWrapper& w = threadlocal_detail::StaticMeta::get(id_); diff --git a/folly/detail/ThreadLocalDetail.h b/folly/detail/ThreadLocalDetail.h index 423b0f2d..b883861a 100644 --- a/folly/detail/ThreadLocalDetail.h +++ b/folly/detail/ThreadLocalDetail.h @@ -77,13 +77,19 @@ struct ElementWrapper { if (ptr != nullptr) { DCHECK(deleter != nullptr); deleter->dispose(ptr, mode); - if (ownsDeleter) { - delete deleter; - } - ptr = nullptr; - deleter = nullptr; - ownsDeleter = false; + + cleanup(); + } + } + + void* release() { + auto retPtr = ptr; + + if (ptr != nullptr) { + cleanup(); } + + return retPtr; } template @@ -114,6 +120,15 @@ struct ElementWrapper { } } + void cleanup() { + if (ownsDeleter) { + delete deleter; + } + ptr = nullptr; + deleter = nullptr; + ownsDeleter = false; + } + void* ptr; DeleterBase* deleter; bool ownsDeleter; diff --git a/folly/test/ThreadLocalTest.cpp b/folly/test/ThreadLocalTest.cpp index 4a25b058..332fa80e 100644 --- a/folly/test/ThreadLocalTest.cpp +++ b/folly/test/ThreadLocalTest.cpp @@ -86,6 +86,21 @@ TEST(ThreadLocalPtr, resetNull) { EXPECT_FALSE(tl); } +TEST(ThreadLocalPtr, TestRelease) { + Widget::totalVal_ = 0; + ThreadLocalPtr w; + std::unique_ptr wPtr; + std::thread([&w, &wPtr]() { + w.reset(new Widget()); + w.get()->val_ += 10; + + wPtr.reset(w.release()); + }).join(); + EXPECT_EQ(0, Widget::totalVal_); + wPtr.reset(); + EXPECT_EQ(10, Widget::totalVal_); +} + // Test deleting the ThreadLocalPtr object TEST(ThreadLocalPtr, CustomDeleter2) { Widget::totalVal_ = 0; -- 2.34.1