1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include <atomic> |
6 | #include <thread> |
7 | |
8 | #include "flutter/fml/macros.h" |
9 | #include "flutter/fml/thread_local.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | namespace { |
13 | |
14 | class Box { |
15 | public: |
16 | explicit Box(int value, std::atomic_int* destroys = nullptr) |
17 | : value_(value), destroys_(destroys) {} |
18 | ~Box() { |
19 | if (destroys_) { |
20 | ++*destroys_; |
21 | } |
22 | } |
23 | |
24 | int value() const { return value_; } |
25 | |
26 | private: |
27 | int value_; |
28 | std::atomic_int* destroys_; |
29 | |
30 | FML_DISALLOW_COPY_AND_ASSIGN(Box); |
31 | }; |
32 | |
33 | FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<Box> local; |
34 | |
35 | } // namespace |
36 | |
37 | TEST(ThreadLocal, SimpleInitialization) { |
38 | std::thread thread([&] { |
39 | ASSERT_EQ(local.get(), nullptr); |
40 | auto value = 100; |
41 | local.reset(new Box(value)); |
42 | ASSERT_EQ(local.get()->value(), value); |
43 | }); |
44 | thread.join(); |
45 | } |
46 | |
47 | TEST(ThreadLocal, SimpleInitializationCheckInAnother) { |
48 | std::thread thread([&] { |
49 | ASSERT_EQ(local.get(), nullptr); |
50 | auto value = 100; |
51 | local.reset(new Box(value)); |
52 | ASSERT_EQ(local.get()->value(), value); |
53 | std::thread thread2([&]() { ASSERT_EQ(local.get(), nullptr); }); |
54 | thread2.join(); |
55 | }); |
56 | thread.join(); |
57 | } |
58 | |
59 | TEST(ThreadLocal, DestroyCallback) { |
60 | std::atomic_int destroys{0}; |
61 | std::thread thread([&] { |
62 | ASSERT_EQ(local.get(), nullptr); |
63 | auto value = 100; |
64 | local.reset(new Box(value, &destroys)); |
65 | ASSERT_EQ(local.get()->value(), value); |
66 | ASSERT_EQ(destroys.load(), 0); |
67 | }); |
68 | thread.join(); |
69 | ASSERT_EQ(destroys.load(), 1); |
70 | } |
71 | |
72 | TEST(ThreadLocal, DestroyCallback2) { |
73 | std::atomic_int destroys{0}; |
74 | std::thread thread([&] { |
75 | local.reset(new Box(100, &destroys)); |
76 | ASSERT_EQ(local.get()->value(), 100); |
77 | ASSERT_EQ(destroys.load(), 0); |
78 | local.reset(new Box(200, &destroys)); |
79 | ASSERT_EQ(local.get()->value(), 200); |
80 | ASSERT_EQ(destroys.load(), 1); |
81 | }); |
82 | thread.join(); |
83 | ASSERT_EQ(destroys.load(), 2); |
84 | } |
85 | |
86 | TEST(ThreadLocal, DestroyThreadTimeline) { |
87 | std::atomic_int destroys{0}; |
88 | std::thread thread([&] { |
89 | std::thread thread2([&]() { |
90 | local.reset(new Box(100, &destroys)); |
91 | ASSERT_EQ(local.get()->value(), 100); |
92 | ASSERT_EQ(destroys.load(), 0); |
93 | local.reset(new Box(200, &destroys)); |
94 | ASSERT_EQ(local.get()->value(), 200); |
95 | ASSERT_EQ(destroys.load(), 1); |
96 | }); |
97 | ASSERT_EQ(local.get(), nullptr); |
98 | thread2.join(); |
99 | ASSERT_EQ(local.get(), nullptr); |
100 | ASSERT_EQ(destroys.load(), 2); |
101 | }); |
102 | thread.join(); |
103 | ASSERT_EQ(destroys.load(), 2); |
104 | } |
105 | |