OSDN Git Service

Add one simple thread local storage test.
[android-x86/bionic.git] / tests / thread_local_test.cpp
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <gtest/gtest.h>
18
19 #ifdef __GNUC__
20 // Gcc has a bug with -O -fdata-section for the arm target: http://b/22772147.
21 // Until that bug is fixed, disable optimization since
22 // it is not essential for this test.
23 #pragma GCC optimize("-O0")
24 #endif
25
26 __thread int local_var = 100;
27 int shared_var = 200;
28
29 static void reset_vars() {
30   local_var = 1000;
31   shared_var = 2000;
32   // local_var should be reset by threads
33 }
34
35 typedef void* (*MyThread)(void*);
36
37 static void* inc_shared_var(void* p) {
38   int *data = reinterpret_cast<int*>(p);
39   shared_var++;
40   *data = shared_var;
41   return nullptr;
42 }
43
44 static void* inc_local_var(void* p) {
45   int *data = reinterpret_cast<int*>(p);
46   local_var++;
47   *data = local_var;
48   return nullptr;
49 }
50
51 static int run_one_thread(MyThread foo) {
52   pthread_t t;
53   int data;
54   int error = pthread_create(&t, nullptr, foo, &data);
55   if (!error)
56       error = pthread_join(t, nullptr);
57   return error ? error : data;
58 }
59
60 TEST(thread_local_storage, shared) {
61   reset_vars();
62   ASSERT_EQ(local_var, 1000);
63   ASSERT_EQ(shared_var, 2000);
64
65   // Update shared_var, local_var remains 1000.
66   ASSERT_EQ(run_one_thread(inc_shared_var), 2001);
67   ASSERT_EQ(local_var, 1000);
68   ASSERT_EQ(shared_var, 2001);
69
70   ASSERT_EQ(run_one_thread(inc_shared_var), 2002);
71   ASSERT_EQ(local_var, 1000);
72   ASSERT_EQ(shared_var, 2002);
73
74   ASSERT_EQ(run_one_thread(inc_shared_var), 2003);
75   ASSERT_EQ(local_var, 1000);
76   ASSERT_EQ(shared_var, 2003);
77 }
78
79 TEST(thread_local_storage, local) {
80   reset_vars();
81   ASSERT_EQ(local_var, 1000);
82   ASSERT_EQ(shared_var, 2000);
83
84   // When a child thread updates its own TLS variable,
85   // this thread's local_var and shared_var are not changed.
86   // TLS local_var is initialized to 100 in a thread.
87   ASSERT_EQ(run_one_thread(inc_local_var), 101);
88   ASSERT_EQ(local_var, 1000);
89   ASSERT_EQ(shared_var, 2000);
90
91   ASSERT_EQ(run_one_thread(inc_local_var), 101);
92   ASSERT_EQ(local_var, 1000);
93   ASSERT_EQ(shared_var, 2000);
94
95   ASSERT_EQ(run_one_thread(inc_local_var), 101);
96   ASSERT_EQ(local_var, 1000);
97   ASSERT_EQ(shared_var, 2000);
98 }
99
100 // Test TLS initialization of more complicated type, array of struct.
101 struct Point {
102   int x, y;
103 };
104
105 typedef Point Triangle[3];
106
107 __thread Triangle local_triangle = {{10,10}, {20,20}, {30,30}};
108 Triangle shared_triangle = {{1,1}, {2,2}, {3,3}};
109
110 static void reset_triangle() {
111   static const Triangle t1 = {{3,3}, {4,4}, {5,5}};
112   static const Triangle t2 = {{2,2}, {3,3}, {4,4}};
113   memcpy(local_triangle, t1, sizeof(local_triangle));
114   memcpy(shared_triangle, t2, sizeof(shared_triangle));
115 }
116
117 static void* move_shared_triangle(void* p) {
118   int *data = reinterpret_cast<int*>(p);
119   shared_triangle[1].y++;
120   *data = shared_triangle[1].y;
121   return nullptr;
122 }
123
124 static void* move_local_triangle(void* p) {
125   int *data = reinterpret_cast<int*>(p);
126   local_triangle[1].y++;
127   *data = local_triangle[1].y;
128   return nullptr;
129 }
130
131 TEST(thread_local_storage, shared_triangle) {
132   reset_triangle();
133   ASSERT_EQ(local_triangle[1].y, 4);
134   ASSERT_EQ(shared_triangle[1].y, 3);
135
136   // Update shared_triangle, local_triangle remains 1000.
137   ASSERT_EQ(run_one_thread(move_shared_triangle), 4);
138   ASSERT_EQ(local_triangle[1].y, 4);
139   ASSERT_EQ(shared_triangle[1].y, 4);
140
141   ASSERT_EQ(run_one_thread(move_shared_triangle), 5);
142   ASSERT_EQ(local_triangle[1].y, 4);
143   ASSERT_EQ(shared_triangle[1].y, 5);
144
145   ASSERT_EQ(run_one_thread(move_shared_triangle), 6);
146   ASSERT_EQ(local_triangle[1].y, 4);
147   ASSERT_EQ(shared_triangle[1].y, 6);
148 }
149
150 TEST(thread_local_storage, local_triangle) {
151   reset_triangle();
152   ASSERT_EQ(local_triangle[1].y, 4);
153   ASSERT_EQ(shared_triangle[1].y, 3);
154
155   // Update local_triangle, parent thread's
156   // shared_triangle and local_triangle are unchanged.
157   ASSERT_EQ(run_one_thread(move_local_triangle), 21);
158   ASSERT_EQ(local_triangle[1].y, 4);
159   ASSERT_EQ(shared_triangle[1].y, 3);
160
161   ASSERT_EQ(run_one_thread(move_local_triangle), 21);
162   ASSERT_EQ(local_triangle[1].y, 4);
163   ASSERT_EQ(shared_triangle[1].y, 3);
164
165   ASSERT_EQ(run_one_thread(move_local_triangle), 21);
166   ASSERT_EQ(local_triangle[1].y, 4);
167   ASSERT_EQ(shared_triangle[1].y, 3);
168 }