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

Commit e2abe84

Browse files
committed
Replace ThreadLocal with ThreadLocalUniquePtr<T>
Fixes flutter/flutter#31292.
1 parent bd8c5b1 commit e2abe84

File tree

7 files changed

+135
-235
lines changed

7 files changed

+135
-235
lines changed

flow/export_node.cc

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ namespace {
1111
using ExportNodeBindings =
1212
std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ExportNode>>;
1313

14-
FML_THREAD_LOCAL fml::ThreadLocal tls_export_node_bindings([](intptr_t value) {
15-
delete reinterpret_cast<ExportNodeBindings*>(value);
16-
});
14+
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ExportNodeBindings>
15+
tls_export_node_bindings;
1716

1817
} // namespace
1918

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

35-
auto* bindings =
36-
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
33+
auto* bindings = tls_export_node_bindings.get();
3734
FML_DCHECK(bindings);
3835
FML_DCHECK(bindings->find(id) == bindings->end());
3936

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

4542
void ExportNode::Destroy(zx_koid_t id) {
46-
auto* bindings =
47-
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
43+
auto* bindings = tls_export_node_bindings.get();
4844
FML_DCHECK(bindings);
4945

5046
bindings->erase(id);
5147
}
5248

5349
ExportNode* ExportNode::FromId(zx_koid_t id) {
54-
auto* bindings =
55-
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
50+
auto* bindings = tls_export_node_bindings.get();
5651
if (!bindings) {
5752
return nullptr;
5853
}

flow/view_holder.cc

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ namespace {
1111
using ViewHolderBindings =
1212
std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ViewHolder>>;
1313

14-
FML_THREAD_LOCAL fml::ThreadLocal tls_view_holder_bindings([](intptr_t value) {
15-
delete reinterpret_cast<ViewHolderBindings*>(value);
16-
});
14+
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ViewHolderBindings>
15+
tls_view_holder_bindings;
1716

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

73-
auto* bindings =
74-
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
71+
auto* bindings = tls_view_holder_bindings.get();
7572
FML_DCHECK(bindings);
7673
FML_DCHECK(bindings->find(id) == bindings->end());
7774

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

8481
void ViewHolder::Destroy(zx_koid_t id) {
85-
auto* bindings =
86-
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
82+
auto* bindings = tls_view_holder_bindings.get();
8783
FML_DCHECK(bindings);
8884

8985
bindings->erase(id);
9086
}
9187

9288
ViewHolder* ViewHolder::FromId(zx_koid_t id) {
93-
auto* bindings =
94-
reinterpret_cast<ViewHolderBindings*>(tls_view_holder_bindings.Get());
89+
auto* bindings = tls_view_holder_bindings.get();
9590
if (!bindings) {
9691
return nullptr;
9792
}

fml/message_loop.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,26 @@
1515

1616
namespace fml {
1717

18-
FML_THREAD_LOCAL ThreadLocal tls_message_loop([](intptr_t value) {
19-
delete reinterpret_cast<MessageLoop*>(value);
20-
});
18+
FML_THREAD_LOCAL ThreadLocalUniquePtr<MessageLoop> tls_message_loop;
2119

2220
MessageLoop& MessageLoop::GetCurrent() {
23-
auto* loop = reinterpret_cast<MessageLoop*>(tls_message_loop.Get());
21+
auto* loop = tls_message_loop.get();
2422
FML_CHECK(loop != nullptr)
2523
<< "MessageLoop::EnsureInitializedForCurrentThread was not called on "
2624
"this thread prior to message loop use.";
2725
return *loop;
2826
}
2927

3028
void MessageLoop::EnsureInitializedForCurrentThread() {
31-
if (tls_message_loop.Get() != 0) {
29+
if (tls_message_loop.get() != nullptr) {
3230
// Already initialized.
3331
return;
3432
}
35-
tls_message_loop.Set(reinterpret_cast<intptr_t>(new MessageLoop()));
33+
tls_message_loop.reset(new MessageLoop());
3634
}
3735

3836
bool MessageLoop::IsInitializedForCurrentThread() {
39-
return tls_message_loop.Get() != 0;
37+
return tls_message_loop.get() != nullptr;
4038
}
4139

4240
MessageLoop::MessageLoop()

fml/thread_local.cc

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,32 @@
44

55
#include "flutter/fml/thread_local.h"
66

7-
namespace fml {
8-
97
#if FML_THREAD_LOCAL_PTHREADS
108

11-
ThreadLocal::ThreadLocal() : ThreadLocal(nullptr) {}
12-
13-
ThreadLocal::ThreadLocal(ThreadLocalDestroyCallback destroy)
14-
: destroy_(destroy) {
15-
auto callback =
16-
reinterpret_cast<void (*)(void*)>(&ThreadLocal::ThreadLocalDestroy);
17-
FML_CHECK(pthread_key_create(&_key, callback) == 0);
18-
}
19-
20-
ThreadLocal::~ThreadLocal() {
21-
// This will NOT call the destroy callbacks on thread local values still
22-
// active in other threads. Those must be cleared manually. The usage
23-
// of this class should be similar to the thread_local keyword but with
24-
// with a static storage specifier
9+
#include "flutter/fml/logging.h"
2510

26-
// Collect the container
27-
delete reinterpret_cast<Box*>(pthread_getspecific(_key));
11+
namespace fml {
12+
namespace internal {
2813

29-
// Finally, collect the key
30-
FML_CHECK(pthread_key_delete(_key) == 0);
14+
ThreadLocalPointer::ThreadLocalPointer(void (*destroy)(void*)) {
15+
FML_CHECK(pthread_key_create(&key_, destroy) == 0);
3116
}
3217

33-
ThreadLocal::Box::Box(ThreadLocalDestroyCallback destroy, intptr_t value)
34-
: destroy_(destroy), value_(value) {}
35-
36-
ThreadLocal::Box::~Box() = default;
37-
38-
#else // FML_THREAD_LOCAL_PTHREADS
39-
40-
ThreadLocal::ThreadLocal() : ThreadLocal(nullptr) {}
41-
42-
ThreadLocal::ThreadLocal(ThreadLocalDestroyCallback destroy)
43-
: destroy_(destroy), value_(0) {}
44-
45-
void ThreadLocal::Set(intptr_t value) {
46-
if (value_ == value) {
47-
return;
48-
}
49-
50-
if (value_ != 0 && destroy_) {
51-
destroy_(value_);
52-
}
53-
54-
value_ = value;
18+
ThreadLocalPointer::~ThreadLocalPointer() {
19+
FML_CHECK(pthread_key_delete(key_) == 0);
5520
}
5621

57-
intptr_t ThreadLocal::Get() {
58-
return value_;
22+
void* ThreadLocalPointer::get() const {
23+
return pthread_getspecific(key_);
5924
}
6025

61-
ThreadLocal::~ThreadLocal() {
62-
if (value_ != 0 && destroy_) {
63-
destroy_(value_);
64-
}
26+
void* ThreadLocalPointer::swap(void* ptr) {
27+
void* old_ptr = get();
28+
FML_CHECK(pthread_setspecific(key_, ptr) == 0);
29+
return old_ptr;
6530
}
6631

67-
#endif // FML_THREAD_LOCAL_PTHREADS
68-
32+
} // namespace internal
6933
} // namespace fml
34+
35+
#endif // FML_THREAD_LOCAL_PTHREADS

fml/thread_local.h

Lines changed: 33 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
#ifndef FLUTTER_FML_THREAD_LOCAL_H_
6-
#define FLUTTER_FML_THREAD_LOCAL_H_
5+
#ifndef FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_
6+
#define FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_
77

8-
#include <functional>
8+
#include <memory>
99

1010
#include "flutter/fml/build_config.h"
11-
#include "flutter/fml/logging.h"
1211
#include "flutter/fml/macros.h"
1312

1413
#define FML_THREAD_LOCAL_PTHREADS OS_MACOSX || OS_LINUX || OS_ANDROID
@@ -19,103 +18,60 @@
1918

2019
namespace fml {
2120

22-
using ThreadLocalDestroyCallback = std::function<void(intptr_t)>;
23-
2421
#if FML_THREAD_LOCAL_PTHREADS
2522

26-
// thread_local is unavailable and we have to resort to pthreads.
27-
2823
#define FML_THREAD_LOCAL static
2924

30-
class ThreadLocal {
31-
private:
32-
class Box {
33-
public:
34-
Box(ThreadLocalDestroyCallback destroy, intptr_t value);
35-
36-
~Box();
25+
namespace internal {
3726

38-
intptr_t Value() const { return value_; }
39-
40-
void SetValue(intptr_t value) {
41-
if (value == value_) {
42-
return;
43-
}
44-
45-
DestroyValue();
46-
value_ = value;
47-
}
27+
class ThreadLocalPointer {
28+
public:
29+
ThreadLocalPointer(void (*destroy)(void*));
30+
~ThreadLocalPointer();
4831

49-
void DestroyValue() {
50-
if (destroy_) {
51-
destroy_(value_);
52-
}
53-
}
32+
void* get() const;
33+
void* swap(void* ptr);
5434

55-
private:
56-
ThreadLocalDestroyCallback destroy_;
57-
intptr_t value_;
35+
private:
36+
pthread_key_t key_;
5837

59-
FML_DISALLOW_COPY_AND_ASSIGN(Box);
60-
};
38+
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer);
39+
};
6140

62-
static inline void ThreadLocalDestroy(void* value) {
63-
FML_CHECK(value != nullptr);
64-
auto* box = reinterpret_cast<Box*>(value);
65-
box->DestroyValue();
66-
delete box;
67-
}
41+
} // namespace internal
6842

43+
template <typename T>
44+
class ThreadLocalUniquePtr {
6945
public:
70-
ThreadLocal();
71-
72-
ThreadLocal(ThreadLocalDestroyCallback destroy);
73-
74-
void Set(intptr_t value) {
75-
auto* box = reinterpret_cast<Box*>(pthread_getspecific(_key));
76-
if (box == nullptr) {
77-
box = new Box(destroy_, value);
78-
FML_CHECK(pthread_setspecific(_key, box) == 0);
79-
} else {
80-
box->SetValue(value);
81-
}
82-
}
83-
84-
intptr_t Get() {
85-
auto* box = reinterpret_cast<Box*>(pthread_getspecific(_key));
86-
return box != nullptr ? box->Value() : 0;
87-
}
46+
ThreadLocalUniquePtr() : ptr_(destroy) {}
8847

89-
~ThreadLocal();
48+
T* get() const { return reinterpret_cast<T*>(ptr_.get()); }
49+
void reset(T* ptr) { destroy(ptr_.swap(ptr)); }
9050

9151
private:
92-
pthread_key_t _key;
93-
ThreadLocalDestroyCallback destroy_;
52+
static void destroy(void* ptr) { delete reinterpret_cast<T*>(ptr); }
9453

95-
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocal);
54+
internal::ThreadLocalPointer ptr_;
55+
56+
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalUniquePtr);
9657
};
9758

9859
#else // FML_THREAD_LOCAL_PTHREADS
9960

100-
#define FML_THREAD_LOCAL thread_local
61+
#define FML_THREAD_LOCAL static thread_local
10162

102-
class ThreadLocal {
63+
template <typename T>
64+
class ThreadLocalUniquePtr {
10365
public:
104-
ThreadLocal();
105-
106-
ThreadLocal(ThreadLocalDestroyCallback destroy);
107-
108-
void Set(intptr_t value);
109-
110-
intptr_t Get();
66+
ThreadLocalUniquePtr() = default;
11167

112-
~ThreadLocal();
68+
T* get() const { return ptr_.get(); }
69+
void reset(T* ptr) { ptr_.reset(ptr); }
11370

11471
private:
115-
ThreadLocalDestroyCallback destroy_;
116-
intptr_t value_;
72+
std::unique_ptr<T> ptr_;
11773

118-
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocal);
74+
FML_DISALLOW_COPY_AND_ASSIGN(ThreadLocalUniquePtr);
11975
};
12076

12177
#endif // FML_THREAD_LOCAL_PTHREADS
@@ -128,4 +84,4 @@ class ThreadLocal {
12884

12985
} // namespace fml
13086

131-
#endif // FLUTTER_FML_THREAD_LOCAL_H_
87+
#endif // FLUTTER_FML_THREAD_LOCAL_UNIQUE_PTR_H_

0 commit comments

Comments
 (0)