Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Replace ThreadLocal with ThreadLocalUniquePtr<T> #8659

Merged
merged 1 commit into from
Apr 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions flow/export_node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ namespace {
using ExportNodeBindings =
std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ExportNode>>;

FML_THREAD_LOCAL fml::ThreadLocal tls_export_node_bindings([](intptr_t value) {
delete reinterpret_cast<ExportNodeBindings*>(value);
});
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ExportNodeBindings>
tls_export_node_bindings;

} // namespace

Expand All @@ -27,13 +26,11 @@ ExportNode::ExportNode(zx::eventpair export_token)
void ExportNode::Create(zx_koid_t id, zx::eventpair export_token) {
// This GPU thread contains at least 1 ViewHolder. Initialize the per-thread
// bindings.
if (tls_export_node_bindings.Get() == 0) {
tls_export_node_bindings.Set(
reinterpret_cast<intptr_t>(new ExportNodeBindings()));
if (tls_export_node_bindings.get() == nullptr) {
tls_export_node_bindings.reset(new ExportNodeBindings());
}

auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
auto* bindings = tls_export_node_bindings.get();
FML_DCHECK(bindings);
FML_DCHECK(bindings->find(id) == bindings->end());

Expand All @@ -43,16 +40,14 @@ void ExportNode::Create(zx_koid_t id, zx::eventpair export_token) {
}

void ExportNode::Destroy(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
auto* bindings = tls_export_node_bindings.get();
FML_DCHECK(bindings);

bindings->erase(id);
}

ExportNode* ExportNode::FromId(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
auto* bindings = tls_export_node_bindings.get();
if (!bindings) {
return nullptr;
}
Expand Down
19 changes: 7 additions & 12 deletions flow/view_holder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ namespace {
using ViewHolderBindings =
std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ViewHolder>>;

FML_THREAD_LOCAL fml::ThreadLocal tls_view_holder_bindings([](intptr_t value) {
delete reinterpret_cast<ViewHolderBindings*>(value);
});
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ViewHolderBindings>
tls_view_holder_bindings;

fuchsia::ui::gfx::ViewProperties ToViewProperties(float width,
float height,
Expand Down Expand Up @@ -65,13 +64,11 @@ void ViewHolder::Create(zx_koid_t id,
BindCallback on_bind_callback) {
// This GPU thread contains at least 1 ViewHolder. Initialize the per-thread
// bindings.
if (tls_view_holder_bindings.Get() == 0) {
tls_view_holder_bindings.Set(
reinterpret_cast<intptr_t>(new ViewHolderBindings()));
if (tls_view_holder_bindings.get() == nullptr) {
tls_view_holder_bindings.reset(new ViewHolderBindings());
}

auto* bindings =
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
auto* bindings = tls_view_holder_bindings.get();
FML_DCHECK(bindings);
FML_DCHECK(bindings->find(id) == bindings->end());

Expand All @@ -82,16 +79,14 @@ void ViewHolder::Create(zx_koid_t id,
}

void ViewHolder::Destroy(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
auto* bindings = tls_view_holder_bindings.get();
FML_DCHECK(bindings);

bindings->erase(id);
}

ViewHolder* ViewHolder::FromId(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
auto* bindings = tls_view_holder_bindings.get();
if (!bindings) {
return nullptr;
}
Expand Down
12 changes: 5 additions & 7 deletions fml/message_loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,26 @@

namespace fml {

FML_THREAD_LOCAL ThreadLocal tls_message_loop([](intptr_t value) {
delete reinterpret_cast<MessageLoop*>(value);
});
FML_THREAD_LOCAL ThreadLocalUniquePtr<MessageLoop> tls_message_loop;

MessageLoop& MessageLoop::GetCurrent() {
auto* loop = reinterpret_cast<MessageLoop*>(tls_message_loop.Get());
auto* loop = tls_message_loop.get();
FML_CHECK(loop != nullptr)
<< "MessageLoop::EnsureInitializedForCurrentThread was not called on "
"this thread prior to message loop use.";
return *loop;
}

void MessageLoop::EnsureInitializedForCurrentThread() {
if (tls_message_loop.Get() != 0) {
if (tls_message_loop.get() != nullptr) {
// Already initialized.
return;
}
tls_message_loop.Set(reinterpret_cast<intptr_t>(new MessageLoop()));
tls_message_loop.reset(new MessageLoop());
}

bool MessageLoop::IsInitializedForCurrentThread() {
return tls_message_loop.Get() != 0;
return tls_message_loop.get() != nullptr;
}

MessageLoop::MessageLoop()
Expand Down
66 changes: 16 additions & 50 deletions fml/thread_local.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,32 @@

#include "flutter/fml/thread_local.h"

namespace fml {

#if FML_THREAD_LOCAL_PTHREADS

ThreadLocal::ThreadLocal() : ThreadLocal(nullptr) {}

ThreadLocal::ThreadLocal(ThreadLocalDestroyCallback destroy)
: destroy_(destroy) {
auto callback =
reinterpret_cast<void (*)(void*)>(&ThreadLocal::ThreadLocalDestroy);
FML_CHECK(pthread_key_create(&_key, callback) == 0);
}

ThreadLocal::~ThreadLocal() {
// This will NOT call the destroy callbacks on thread local values still
// active in other threads. Those must be cleared manually. The usage
// of this class should be similar to the thread_local keyword but with
// with a static storage specifier
#include "flutter/fml/logging.h"

// Collect the container
delete reinterpret_cast<Box*>(pthread_getspecific(_key));
namespace fml {
namespace internal {

// Finally, collect the key
FML_CHECK(pthread_key_delete(_key) == 0);
ThreadLocalPointer::ThreadLocalPointer(void (*destroy)(void*)) {
FML_CHECK(pthread_key_create(&key_, destroy) == 0);
}

ThreadLocal::Box::Box(ThreadLocalDestroyCallback destroy, intptr_t value)
: destroy_(destroy), value_(value) {}

ThreadLocal::Box::~Box() = default;

#else // FML_THREAD_LOCAL_PTHREADS

ThreadLocal::ThreadLocal() : ThreadLocal(nullptr) {}

ThreadLocal::ThreadLocal(ThreadLocalDestroyCallback destroy)
: destroy_(destroy), value_(0) {}

void ThreadLocal::Set(intptr_t value) {
if (value_ == value) {
return;
}

if (value_ != 0 && destroy_) {
destroy_(value_);
}

value_ = value;
ThreadLocalPointer::~ThreadLocalPointer() {
FML_CHECK(pthread_key_delete(key_) == 0);
}

intptr_t ThreadLocal::Get() {
return value_;
void* ThreadLocalPointer::get() const {
return pthread_getspecific(key_);
}

ThreadLocal::~ThreadLocal() {
if (value_ != 0 && destroy_) {
destroy_(value_);
}
void* ThreadLocalPointer::swap(void* ptr) {
void* old_ptr = get();
FML_CHECK(pthread_setspecific(key_, ptr) == 0);
return old_ptr;
}

#endif // FML_THREAD_LOCAL_PTHREADS

} // namespace internal
} // namespace fml

#endif // FML_THREAD_LOCAL_PTHREADS
110 changes: 33 additions & 77 deletions fml/thread_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_THREAD_LOCAL_H_
#define FLUTTER_FML_THREAD_LOCAL_H_
#ifndef FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_
#define FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_

#include <functional>
#include <memory>

#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"

#define FML_THREAD_LOCAL_PTHREADS OS_MACOSX || OS_LINUX || OS_ANDROID
Expand All @@ -19,103 +18,60 @@

namespace fml {

using ThreadLocalDestroyCallback = std::function<void(intptr_t)>;

#if FML_THREAD_LOCAL_PTHREADS

// thread_local is unavailable and we have to resort to pthreads.

#define FML_THREAD_LOCAL static

class ThreadLocal {
private:
class Box {
public:
Box(ThreadLocalDestroyCallback destroy, intptr_t value);

~Box();
namespace internal {

intptr_t Value() const { return value_; }

void SetValue(intptr_t value) {
if (value == value_) {
return;
}

DestroyValue();
value_ = value;
}
class ThreadLocalPointer {
public:
ThreadLocalPointer(void (*destroy)(void*));
~ThreadLocalPointer();

void DestroyValue() {
if (destroy_) {
destroy_(value_);
}
}
void* get() const;
void* swap(void* ptr);

private:
ThreadLocalDestroyCallback destroy_;
intptr_t value_;
private:
pthread_key_t key_;

FML_DISALLOW_COPY_AND_ASSIGN(Box);
};
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer);
};

static inline void ThreadLocalDestroy(void* value) {
FML_CHECK(value != nullptr);
auto* box = reinterpret_cast<Box*>(value);
box->DestroyValue();
delete box;
}
} // namespace internal

template <typename T>
class ThreadLocalUniquePtr {
public:
ThreadLocal();

ThreadLocal(ThreadLocalDestroyCallback destroy);

void Set(intptr_t value) {
auto* box = reinterpret_cast<Box*>(pthread_getspecific(_key));
if (box == nullptr) {
box = new Box(destroy_, value);
FML_CHECK(pthread_setspecific(_key, box) == 0);
} else {
box->SetValue(value);
}
}

intptr_t Get() {
auto* box = reinterpret_cast<Box*>(pthread_getspecific(_key));
return box != nullptr ? box->Value() : 0;
}
ThreadLocalUniquePtr() : ptr_(destroy) {}

~ThreadLocal();
T* get() const { return reinterpret_cast<T*>(ptr_.get()); }
void reset(T* ptr) { destroy(ptr_.swap(ptr)); }

private:
pthread_key_t _key;
ThreadLocalDestroyCallback destroy_;
static void destroy(void* ptr) { delete reinterpret_cast<T*>(ptr); }

FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocal);
internal::ThreadLocalPointer ptr_;

FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalUniquePtr);
};

#else // FML_THREAD_LOCAL_PTHREADS

#define FML_THREAD_LOCAL thread_local
#define FML_THREAD_LOCAL static thread_local

class ThreadLocal {
template <typename T>
class ThreadLocalUniquePtr {
public:
ThreadLocal();

ThreadLocal(ThreadLocalDestroyCallback destroy);

void Set(intptr_t value);

intptr_t Get();
ThreadLocalUniquePtr() = default;

~ThreadLocal();
T* get() const { return ptr_.get(); }
void reset(T* ptr) { ptr_.reset(ptr); }

private:
ThreadLocalDestroyCallback destroy_;
intptr_t value_;
std::unique_ptr<T> ptr_;

FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocal);
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalUniquePtr);
};

#endif // FML_THREAD_LOCAL_PTHREADS
Expand All @@ -128,4 +84,4 @@ class ThreadLocal {

} // namespace fml

#endif // FLUTTER_FML_THREAD_LOCAL_H_
#endif // FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_
Loading