Commit b51f8cd7 authored by Akshay Vaidya's avatar Akshay Vaidya Committed by Dave Watson

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
parent 870912b8
...@@ -165,6 +165,13 @@ class ThreadLocalPtr { ...@@ -165,6 +165,13 @@ class ThreadLocalPtr {
return *get(); return *get();
} }
T* release() {
threadlocal_detail::ElementWrapper& w =
threadlocal_detail::StaticMeta<Tag>::get(id_);
return static_cast<T*>(w.release());
}
void reset(T* newPtr = nullptr) { void reset(T* newPtr = nullptr) {
threadlocal_detail::ElementWrapper& w = threadlocal_detail::ElementWrapper& w =
threadlocal_detail::StaticMeta<Tag>::get(id_); threadlocal_detail::StaticMeta<Tag>::get(id_);
......
...@@ -77,13 +77,19 @@ struct ElementWrapper { ...@@ -77,13 +77,19 @@ struct ElementWrapper {
if (ptr != nullptr) { if (ptr != nullptr) {
DCHECK(deleter != nullptr); DCHECK(deleter != nullptr);
deleter->dispose(ptr, mode); deleter->dispose(ptr, mode);
if (ownsDeleter) {
delete deleter; cleanup();
} }
ptr = nullptr;
deleter = nullptr;
ownsDeleter = false;
} }
void* release() {
auto retPtr = ptr;
if (ptr != nullptr) {
cleanup();
}
return retPtr;
} }
template <class Ptr> template <class Ptr>
...@@ -114,6 +120,15 @@ struct ElementWrapper { ...@@ -114,6 +120,15 @@ struct ElementWrapper {
} }
} }
void cleanup() {
if (ownsDeleter) {
delete deleter;
}
ptr = nullptr;
deleter = nullptr;
ownsDeleter = false;
}
void* ptr; void* ptr;
DeleterBase* deleter; DeleterBase* deleter;
bool ownsDeleter; bool ownsDeleter;
......
...@@ -86,6 +86,21 @@ TEST(ThreadLocalPtr, resetNull) { ...@@ -86,6 +86,21 @@ TEST(ThreadLocalPtr, resetNull) {
EXPECT_FALSE(tl); EXPECT_FALSE(tl);
} }
TEST(ThreadLocalPtr, TestRelease) {
Widget::totalVal_ = 0;
ThreadLocalPtr<Widget> w;
std::unique_ptr<Widget> 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 deleting the ThreadLocalPtr object
TEST(ThreadLocalPtr, CustomDeleter2) { TEST(ThreadLocalPtr, CustomDeleter2) {
Widget::totalVal_ = 0; Widget::totalVal_ = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment