OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <string> | 5 #include <string> |
6 #include <vector> | 6 #include <vector> |
7 | 7 |
8 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
9 #include "base/threading/platform_thread.h" | 9 #include "base/threading/platform_thread.h" |
10 #include "ppapi/c/pp_var.h" | 10 #include "ppapi/c/pp_var.h" |
11 #include "ppapi/c/ppb_var.h" | 11 #include "ppapi/c/ppb_var.h" |
12 #include "ppapi/proxy/ppapi_proxy_test.h" | 12 #include "ppapi/proxy/ppapi_proxy_test.h" |
| 13 #include "ppapi/shared_impl/ppapi_globals.h" |
13 #include "ppapi/shared_impl/ppb_var_shared.h" | 14 #include "ppapi/shared_impl/ppb_var_shared.h" |
14 | 15 |
15 namespace { | 16 namespace { |
16 std::string VarToString(const PP_Var& var, const PPB_Var* ppb_var) { | 17 std::string VarToString(const PP_Var& var, const PPB_Var* ppb_var) { |
17 uint32_t len = 0; | 18 uint32_t len = 0; |
18 const char* utf8 = ppb_var->VarToUtf8(var, &len); | 19 const char* utf8 = ppb_var->VarToUtf8(var, &len); |
19 return std::string(utf8, len); | 20 return std::string(utf8, len); |
20 } | 21 } |
21 const size_t kNumStrings = 100; | 22 const size_t kNumStrings = 100; |
22 const size_t kNumThreads = 20; | 23 const size_t kNumThreads = 20; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 // 3) Spawn kNumThreads 'RemoveVar' threads. Each of these threads releases each | 90 // 3) Spawn kNumThreads 'RemoveVar' threads. Each of these threads releases each |
90 // var once. Once all the threads have finished, there should be no vars | 91 // var once. Once all the threads have finished, there should be no vars |
91 // left. | 92 // left. |
92 class CreateVarThreadDelegate : public base::PlatformThread::Delegate { | 93 class CreateVarThreadDelegate : public base::PlatformThread::Delegate { |
93 public: | 94 public: |
94 // |strings_in|, |vars|, and |strings_out| are arrays, and size is their size. | 95 // |strings_in|, |vars|, and |strings_out| are arrays, and size is their size. |
95 // For each |strings_in[i]|, we will set |vars[i]| using that value. Then we | 96 // For each |strings_in[i]|, we will set |vars[i]| using that value. Then we |
96 // read the var back out to |strings_out[i]|. | 97 // read the var back out to |strings_out[i]|. |
97 CreateVarThreadDelegate(PP_Module pp_module, const std::string* strings_in, | 98 CreateVarThreadDelegate(PP_Module pp_module, const std::string* strings_in, |
98 PP_Var* vars_out, std::string* strings_out, | 99 PP_Var* vars_out, std::string* strings_out, |
99 size_t size) | 100 size_t size, PpapiGlobals* globals) |
100 : pp_module_(pp_module), strings_in_(strings_in), vars_out_(vars_out), | 101 : pp_module_(pp_module), strings_in_(strings_in), vars_out_(vars_out), |
101 strings_out_(strings_out), size_(size) { | 102 strings_out_(strings_out), size_(size), globals_(globals) { |
102 } | 103 } |
103 virtual ~CreateVarThreadDelegate() {} | 104 virtual ~CreateVarThreadDelegate() {} |
104 virtual void ThreadMain() { | 105 virtual void ThreadMain() { |
| 106 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(globals_); |
105 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); | 107 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); |
106 for (size_t i = 0; i < size_; ++i) { | 108 for (size_t i = 0; i < size_; ++i) { |
107 vars_out_[i] = ppb_var->VarFromUtf8(strings_in_[i].c_str(), | 109 vars_out_[i] = ppb_var->VarFromUtf8(strings_in_[i].c_str(), |
108 strings_in_[i].length()); | 110 strings_in_[i].length()); |
109 strings_out_[i] = VarToString(vars_out_[i], ppb_var); | 111 strings_out_[i] = VarToString(vars_out_[i], ppb_var); |
110 } | 112 } |
111 } | 113 } |
112 private: | 114 private: |
113 PP_Module pp_module_; | 115 PP_Module pp_module_; |
114 const std::string* strings_in_; | 116 const std::string* strings_in_; |
115 PP_Var* vars_out_; | 117 PP_Var* vars_out_; |
116 std::string* strings_out_; | 118 std::string* strings_out_; |
117 size_t size_; | 119 size_t size_; |
| 120 PpapiGlobals* globals_; |
118 }; | 121 }; |
119 | 122 |
120 // A thread that will increment and decrement the reference count of every var | 123 // A thread that will increment and decrement the reference count of every var |
121 // multiple times. | 124 // multiple times. |
122 class ChangeRefVarThreadDelegate : public base::PlatformThread::Delegate { | 125 class ChangeRefVarThreadDelegate : public base::PlatformThread::Delegate { |
123 public: | 126 public: |
124 ChangeRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) { | 127 ChangeRefVarThreadDelegate(const std::vector<PP_Var>& vars, |
| 128 PpapiGlobals* globals) |
| 129 : vars_(vars), globals_(globals) { |
125 } | 130 } |
126 virtual ~ChangeRefVarThreadDelegate() {} | 131 virtual ~ChangeRefVarThreadDelegate() {} |
127 virtual void ThreadMain() { | 132 virtual void ThreadMain() { |
| 133 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(globals_); |
128 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); | 134 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); |
129 // Increment and decrement the reference count for each var kRefsToAdd | 135 // Increment and decrement the reference count for each var kRefsToAdd |
130 // times. Note that we always AddRef once before doing the matching Release, | 136 // times. Note that we always AddRef once before doing the matching Release, |
131 // to ensure that we never accidentally release the last reference. | 137 // to ensure that we never accidentally release the last reference. |
132 for (int ref = 0; ref < kRefsToAdd; ++ref) { | 138 for (int ref = 0; ref < kRefsToAdd; ++ref) { |
133 for (size_t i = 0; i < kNumStrings; ++i) { | 139 for (size_t i = 0; i < kNumStrings; ++i) { |
134 ppb_var->AddRef(vars_[i]); | 140 ppb_var->AddRef(vars_[i]); |
135 ppb_var->Release(vars_[i]); | 141 ppb_var->Release(vars_[i]); |
136 } | 142 } |
137 } | 143 } |
138 // Now add 1 ref to each Var. The net result is that all Vars will have a | 144 // Now add 1 ref to each Var. The net result is that all Vars will have a |
139 // ref-count of (kNumThreads + 1) after this. That will allow us to have all | 145 // ref-count of (kNumThreads + 1) after this. That will allow us to have all |
140 // threads release all vars later. | 146 // threads release all vars later. |
141 for (size_t i = 0; i < kNumStrings; ++i) { | 147 for (size_t i = 0; i < kNumStrings; ++i) { |
142 ppb_var->AddRef(vars_[i]); | 148 ppb_var->AddRef(vars_[i]); |
143 } | 149 } |
144 } | 150 } |
145 private: | 151 private: |
146 std::vector<PP_Var> vars_; | 152 std::vector<PP_Var> vars_; |
| 153 PpapiGlobals* globals_; |
147 }; | 154 }; |
148 | 155 |
149 // A thread that will decrement the reference count of every var once. | 156 // A thread that will decrement the reference count of every var once. |
150 class RemoveRefVarThreadDelegate : public base::PlatformThread::Delegate { | 157 class RemoveRefVarThreadDelegate : public base::PlatformThread::Delegate { |
151 public: | 158 public: |
152 RemoveRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) { | 159 RemoveRefVarThreadDelegate(const std::vector<PP_Var>& vars, |
| 160 PpapiGlobals* globals) |
| 161 : vars_(vars), globals_(globals) { |
153 } | 162 } |
154 virtual ~RemoveRefVarThreadDelegate() {} | 163 virtual ~RemoveRefVarThreadDelegate() {} |
155 virtual void ThreadMain() { | 164 virtual void ThreadMain() { |
| 165 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(globals_); |
156 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); | 166 const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); |
157 for (size_t i = 0; i < kNumStrings; ++i) { | 167 for (size_t i = 0; i < kNumStrings; ++i) { |
158 ppb_var->Release(vars_[i]); | 168 ppb_var->Release(vars_[i]); |
159 } | 169 } |
160 } | 170 } |
161 private: | 171 private: |
162 std::vector<PP_Var> vars_; | 172 std::vector<PP_Var> vars_; |
| 173 PpapiGlobals* globals_; |
163 }; | 174 }; |
164 | 175 |
165 } // namespace | 176 } // namespace |
166 | 177 |
167 #ifdef ENABLE_PEPPER_THREADING | 178 #ifdef ENABLE_PEPPER_THREADING |
168 TEST_F(PPB_VarTest, Threads) { | 179 TEST_F(PPB_VarTest, Threads) { |
169 #else | 180 #else |
170 TEST_F(PPB_VarTest, DISABLED_Threads) { | 181 TEST_F(PPB_VarTest, DISABLED_Threads) { |
171 #endif | 182 #endif |
172 std::vector<base::PlatformThreadHandle> create_var_threads(kNumThreads); | 183 std::vector<base::PlatformThreadHandle> create_var_threads(kNumThreads); |
173 std::vector<CreateVarThreadDelegate> create_var_delegates; | 184 std::vector<CreateVarThreadDelegate> create_var_delegates; |
174 // The strings that the threads will re-extract from Vars (so we can check | 185 // The strings that the threads will re-extract from Vars (so we can check |
175 // that they match the original strings). | 186 // that they match the original strings). |
176 std::vector<std::string> strings_out(kNumStrings); | 187 std::vector<std::string> strings_out(kNumStrings); |
177 size_t strings_per_thread = kNumStrings/kNumThreads; | 188 size_t strings_per_thread = kNumStrings/kNumThreads; |
178 // Give each thread an equal slice of strings to turn in to vars. (Except the | 189 // Give each thread an equal slice of strings to turn in to vars. (Except the |
179 // last thread may get fewer if kNumStrings is not evenly divisible by | 190 // last thread may get fewer if kNumStrings is not evenly divisible by |
180 // kNumThreads). | 191 // kNumThreads). |
181 for (size_t slice_start= 0; slice_start < kNumStrings; | 192 for (size_t slice_start= 0; slice_start < kNumStrings; |
182 slice_start += strings_per_thread) { | 193 slice_start += strings_per_thread) { |
183 create_var_delegates.push_back( | 194 create_var_delegates.push_back( |
184 CreateVarThreadDelegate(pp_module(), | 195 CreateVarThreadDelegate(pp_module(), |
185 &test_strings_[slice_start], | 196 &test_strings_[slice_start], |
186 &vars_[slice_start], | 197 &vars_[slice_start], |
187 &strings_out[slice_start], | 198 &strings_out[slice_start], |
188 std::min(strings_per_thread, | 199 std::min(strings_per_thread, |
189 kNumStrings - slice_start))); | 200 kNumStrings - slice_start), |
| 201 GetGlobals())); |
190 } | 202 } |
191 // Now run then join all the threads. | 203 // Now run then join all the threads. |
192 for (size_t i = 0; i < kNumThreads; ++i) | 204 for (size_t i = 0; i < kNumThreads; ++i) |
193 base::PlatformThread::Create(0, &create_var_delegates[i], | 205 base::PlatformThread::Create(0, &create_var_delegates[i], |
194 &create_var_threads[i]); | 206 &create_var_threads[i]); |
195 for (size_t i = 0; i < kNumThreads; ++i) | 207 for (size_t i = 0; i < kNumThreads; ++i) |
196 base::PlatformThread::Join(create_var_threads[i]); | 208 base::PlatformThread::Join(create_var_threads[i]); |
197 // Now check that the strings have the expected values. | 209 // Now check that the strings have the expected values. |
198 EXPECT_EQ(test_strings_, strings_out); | 210 EXPECT_EQ(test_strings_, strings_out); |
199 | 211 |
200 // Tinker with the reference counts in a multithreaded way. | 212 // Tinker with the reference counts in a multithreaded way. |
201 std::vector<base::PlatformThreadHandle> change_ref_var_threads(kNumThreads); | 213 std::vector<base::PlatformThreadHandle> change_ref_var_threads(kNumThreads); |
202 std::vector<ChangeRefVarThreadDelegate> change_ref_var_delegates; | 214 std::vector<ChangeRefVarThreadDelegate> change_ref_var_delegates; |
203 for (size_t i = 0; i < kNumThreads; ++i) | 215 for (size_t i = 0; i < kNumThreads; ++i) |
204 change_ref_var_delegates.push_back(ChangeRefVarThreadDelegate(vars_)); | 216 change_ref_var_delegates.push_back( |
| 217 ChangeRefVarThreadDelegate(vars_, GetGlobals())); |
205 for (size_t i = 0; i < kNumThreads; ++i) { | 218 for (size_t i = 0; i < kNumThreads; ++i) { |
206 base::PlatformThread::Create(0, &change_ref_var_delegates[i], | 219 base::PlatformThread::Create(0, &change_ref_var_delegates[i], |
207 &change_ref_var_threads[i]); | 220 &change_ref_var_threads[i]); |
208 } | 221 } |
209 for (size_t i = 0; i < kNumThreads; ++i) | 222 for (size_t i = 0; i < kNumThreads; ++i) |
210 base::PlatformThread::Join(change_ref_var_threads[i]); | 223 base::PlatformThread::Join(change_ref_var_threads[i]); |
211 | 224 |
212 // Now each var has a refcount of (kNumThreads + 1). Let's decrement each var | 225 // Now each var has a refcount of (kNumThreads + 1). Let's decrement each var |
213 // once so that every 'RemoveRef' thread (spawned below) owns 1 reference, and | 226 // once so that every 'RemoveRef' thread (spawned below) owns 1 reference, and |
214 // when the last one removes a ref, the Var will be deleted. | 227 // when the last one removes a ref, the Var will be deleted. |
215 for (size_t i = 0; i < kNumStrings; ++i) { | 228 for (size_t i = 0; i < kNumStrings; ++i) { |
216 ppb_var_->Release(vars_[i]); | 229 ppb_var_->Release(vars_[i]); |
217 } | 230 } |
218 | 231 |
219 // Check that all vars are still valid and have the values we expect. | 232 // Check that all vars are still valid and have the values we expect. |
220 for (size_t i = 0; i < kNumStrings; ++i) | 233 for (size_t i = 0; i < kNumStrings; ++i) |
221 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); | 234 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); |
222 | 235 |
223 // Remove the last reference counts for all vars. | 236 // Remove the last reference counts for all vars. |
224 std::vector<base::PlatformThreadHandle> remove_ref_var_threads(kNumThreads); | 237 std::vector<base::PlatformThreadHandle> remove_ref_var_threads(kNumThreads); |
225 std::vector<RemoveRefVarThreadDelegate> remove_ref_var_delegates; | 238 std::vector<RemoveRefVarThreadDelegate> remove_ref_var_delegates; |
226 for (size_t i = 0; i < kNumThreads; ++i) | 239 for (size_t i = 0; i < kNumThreads; ++i) |
227 remove_ref_var_delegates.push_back(RemoveRefVarThreadDelegate(vars_)); | 240 remove_ref_var_delegates.push_back( |
| 241 RemoveRefVarThreadDelegate(vars_, GetGlobals())); |
228 for (size_t i = 0; i < kNumThreads; ++i) { | 242 for (size_t i = 0; i < kNumThreads; ++i) { |
229 base::PlatformThread::Create(0, &remove_ref_var_delegates[i], | 243 base::PlatformThread::Create(0, &remove_ref_var_delegates[i], |
230 &remove_ref_var_threads[i]); | 244 &remove_ref_var_threads[i]); |
231 } | 245 } |
232 for (size_t i = 0; i < kNumThreads; ++i) | 246 for (size_t i = 0; i < kNumThreads; ++i) |
233 base::PlatformThread::Join(remove_ref_var_threads[i]); | 247 base::PlatformThread::Join(remove_ref_var_threads[i]); |
234 | 248 |
235 // All the vars should no longer represent valid strings. | 249 // All the vars should no longer represent valid strings. |
236 for (size_t i = 0; i < kNumStrings; ++i) { | 250 for (size_t i = 0; i < kNumStrings; ++i) { |
237 uint32_t len = 10; | 251 uint32_t len = 10; |
238 const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len); | 252 const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len); |
239 EXPECT_EQ(NULL, utf8); | 253 EXPECT_EQ(NULL, utf8); |
240 EXPECT_EQ(0u, len); | 254 EXPECT_EQ(0u, len); |
241 } | 255 } |
242 } | 256 } |
243 | 257 |
244 } // namespace proxy | 258 } // namespace proxy |
245 } // namespace ppapi | 259 } // namespace ppapi |
OLD | NEW |