Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: ppapi/proxy/ppb_var_unittest.cc

Issue 8016008: Make much of the proxy thread-safe with 1 great big lock. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ppapi/proxy/ppb_var_proxy.cc ('k') | ppapi/shared_impl/proxy_lock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "ppapi/c/pp_var.h" 10 #include "ppapi/c/pp_var.h"
10 #include "ppapi/c/ppb_var.h" 11 #include "ppapi/c/ppb_var.h"
11 #include "ppapi/proxy/ppapi_proxy_test.h" 12 #include "ppapi/proxy/ppapi_proxy_test.h"
12 #include "ppapi/proxy/ppb_var_proxy.h" 13 #include "ppapi/proxy/ppb_var_proxy.h"
13 14
14 // TODO(dmichael): Make PPB_Var_Proxy and PluginResourceTracker thread-safe and
15 // add thread-safety tests here.
16
17 namespace { 15 namespace {
18 std::string VarToString(const PP_Var& var, const PPB_Var* ppb_var) { 16 std::string VarToString(const PP_Var& var, const PPB_Var* ppb_var) {
19 uint32_t len = 0; 17 uint32_t len = 0;
20 const char* utf8 = ppb_var->VarToUtf8(var, &len); 18 const char* utf8 = ppb_var->VarToUtf8(var, &len);
21 return std::string(utf8, len); 19 return std::string(utf8, len);
22 } 20 }
21 const size_t kNumStrings = 100;
22 const size_t kNumThreads = 20;
23 const int kRefsToAdd = 20;
23 } // namespace 24 } // namespace
24 25
25 namespace ppapi { 26 namespace ppapi {
26 namespace proxy { 27 namespace proxy {
27 28
28 class PPB_VarTest : public PluginProxyTest { 29 class PPB_VarTest : public PluginProxyTest {
29 public: 30 public:
30 PPB_VarTest() {} 31 PPB_VarTest()
31 }; 32 : test_strings_(kNumStrings), vars_(kNumStrings),
32 33 ppb_var_(GetPPB_Var_Interface()) {
34 // Set the value of test_strings_[i] to "i".
35 for (size_t i = 0; i < kNumStrings; ++i)
36 test_strings_[i] = base::IntToString(i);
37 }
38 protected:
39 std::vector<std::string> test_strings_;
40 std::vector<PP_Var> vars_;
41 const PPB_Var* ppb_var_;
42 };
43
44 // Test basic String operations.
33 TEST_F(PPB_VarTest, Strings) { 45 TEST_F(PPB_VarTest, Strings) {
34 const PPB_Var* ppb_var = GetPPB_Var_Interface(); 46 for (size_t i = 0; i < kNumStrings; ++i) {
35 47 vars_[i] = ppb_var_->VarFromUtf8(pp_module(),
36 // Make a vector of strings, where the value of test_strings[i] is "i". 48 test_strings_[i].c_str(),
37 const int kNumStrings = 5; 49 test_strings_[i].length());
38 std::vector<std::string> test_strings(kNumStrings); 50 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_));
39 for (int i = 0; i < kNumStrings; ++i)
40 test_strings[i] = base::IntToString(i);
41
42 std::vector<PP_Var> vars(kNumStrings);
43 for (int i = 0; i < kNumStrings; ++i) {
44 vars[i] = ppb_var->VarFromUtf8(pp_module(),
45 test_strings[i].c_str(),
46 test_strings[i].length());
47 EXPECT_EQ(test_strings[i], VarToString(vars[i], ppb_var));
48 } 51 }
49 // At this point, they should each have a ref count of 1. Add some more. 52 // At this point, they should each have a ref count of 1. Add some more.
50 const int kRefsToAdd = 3;
51 for (int ref = 0; ref < kRefsToAdd; ++ref) { 53 for (int ref = 0; ref < kRefsToAdd; ++ref) {
52 for (int i = 0; i < kNumStrings; ++i) { 54 for (size_t i = 0; i < kNumStrings; ++i) {
53 ppb_var->AddRef(vars[i]); 55 ppb_var_->AddRef(vars_[i]);
54 // Make sure the string is still there with the right value. 56 // Make sure the string is still there with the right value.
55 EXPECT_EQ(test_strings[i], VarToString(vars[i], ppb_var)); 57 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_));
56 } 58 }
57 } 59 }
58 for (int ref = 0; ref < kRefsToAdd; ++ref) { 60 for (int ref = 0; ref < kRefsToAdd; ++ref) {
59 for (int i = 0; i < kNumStrings; ++i) { 61 for (size_t i = 0; i < kNumStrings; ++i) {
60 ppb_var->Release(vars[i]); 62 ppb_var_->Release(vars_[i]);
61 // Make sure the string is still there with the right value. 63 // Make sure the string is still there with the right value.
62 EXPECT_EQ(test_strings[i], VarToString(vars[i], ppb_var)); 64 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_));
63 } 65 }
64 } 66 }
65 // Now remove the ref counts for each string and make sure they are gone. 67 // Now remove the ref counts for each string and make sure they are gone.
66 for (int i = 0; i < kNumStrings; ++i) { 68 for (size_t i = 0; i < kNumStrings; ++i) {
67 ppb_var->Release(vars[i]); 69 ppb_var_->Release(vars_[i]);
68 uint32_t len = 10; 70 uint32_t len = 10;
69 const char* utf8 = ppb_var->VarToUtf8(vars[i], &len); 71 const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len);
70 EXPECT_EQ(NULL, utf8); 72 EXPECT_EQ(NULL, utf8);
71 EXPECT_EQ(0u, len); 73 EXPECT_EQ(0u, len);
72 } 74 }
75 }
76
77 // PPB_VarTest.Threads tests string operations accessed by multiple threads.
78 namespace {
79 // These three delegate classes which precede the test are for use with
80 // PlatformThread. The test goes roughly like this:
81 // 1) Spawn kNumThreads 'CreateVar' threads, giving each a roughly equal subset
82 // of test_strings_ to 'create'. Each 'CreateVar' thread also converts its
83 // set of vars back in to strings so that the main test thread can verify
84 // their values were correctly converted.
85 // 2) Spawn kNumThreads 'ChangeRefVar' threads. Each of these threads will
86 // incremement & decrement the reference count of ALL vars kRefsToAdd times.
87 // Finally, each thread adds 1 ref count. This leaves each var with a ref-
88 // count of |kNumThreads + 1|. The main test thread removes a ref, leaving
89 // each var with a ref-count of |kNumThreads|.
90 // 3) Spawn kNumThreads 'RemoveVar' threads. Each of these threads releases each
91 // var once. Once all the threads have finished, there should be no vars
92 // left.
93 class CreateVarThreadDelegate : public base::PlatformThread::Delegate {
94 public:
95 // |strings_in|, |vars|, and |strings_out| are arrays, and size is their size.
96 // For each |strings_in[i]|, we will set |vars[i]| using that value. Then we
97 // read the var back out to |strings_out[i]|.
98 CreateVarThreadDelegate(PP_Module pp_module, const std::string* strings_in,
99 PP_Var* vars_out, std::string* strings_out,
100 size_t size)
101 : pp_module_(pp_module), strings_in_(strings_in), vars_out_(vars_out),
102 strings_out_(strings_out), size_(size) {
103 }
104 virtual ~CreateVarThreadDelegate() {}
105 virtual void ThreadMain() {
106 const PPB_Var* ppb_var = ppapi::proxy::GetPPB_Var_Interface();
107 for (size_t i = 0; i < size_; ++i) {
108 vars_out_[i] = ppb_var->VarFromUtf8(pp_module_,
109 strings_in_[i].c_str(),
110 strings_in_[i].length());
111 strings_out_[i] = VarToString(vars_out_[i], ppb_var);
112 }
113 }
114 private:
115 PP_Module pp_module_;
116 const std::string* strings_in_;
117 PP_Var* vars_out_;
118 std::string* strings_out_;
119 size_t size_;
120 };
121
122 // A thread that will increment and decrement the reference count of every var
123 // multiple times.
124 class ChangeRefVarThreadDelegate : public base::PlatformThread::Delegate {
125 public:
126 ChangeRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) {
127 }
128 virtual ~ChangeRefVarThreadDelegate() {}
129 virtual void ThreadMain() {
130 const PPB_Var* ppb_var = ppapi::proxy::GetPPB_Var_Interface();
131 // Increment and decrement the reference count for each var kRefsToAdd
132 // times. Note that we always AddRef once before doing the matching Release,
133 // to ensure that we never accidentally release the last reference.
134 for (int ref = 0; ref < kRefsToAdd; ++ref) {
135 for (size_t i = 0; i < kNumStrings; ++i) {
136 ppb_var->AddRef(vars_[i]);
137 ppb_var->Release(vars_[i]);
138 }
139 }
140 // Now add 1 ref to each Var. The net result is that all Vars will have a
141 // ref-count of (kNumThreads + 1) after this. That will allow us to have all
142 // threads release all vars later.
143 for (size_t i = 0; i < kNumStrings; ++i) {
144 ppb_var->AddRef(vars_[i]);
145 }
146 }
147 private:
148 std::vector<PP_Var> vars_;
149 };
150
151 // A thread that will decrement the reference count of every var once.
152 class RemoveRefVarThreadDelegate : public base::PlatformThread::Delegate {
153 public:
154 RemoveRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) {
155 }
156 virtual ~RemoveRefVarThreadDelegate() {}
157 virtual void ThreadMain() {
158 const PPB_Var* ppb_var = ppapi::proxy::GetPPB_Var_Interface();
159 for (size_t i = 0; i < kNumStrings; ++i) {
160 ppb_var->Release(vars_[i]);
161 }
162 }
163 private:
164 std::vector<PP_Var> vars_;
165 };
166
167 } // namespace
168
169 #ifdef ENABLE_PEPPER_THREADING
170 TEST_F(PPB_VarTest, Threads) {
171 #else
172 TEST_F(PPB_VarTest, DISABLED_Threads) {
173 #endif
174 std::vector<base::PlatformThreadHandle> create_var_threads(kNumThreads);
175 std::vector<CreateVarThreadDelegate> create_var_delegates;
176 // The strings that the threads will re-extract from Vars (so we can check
177 // that they match the original strings).
178 std::vector<std::string> strings_out(kNumStrings);
179 size_t strings_per_thread = kNumStrings/kNumThreads;
180 // Give each thread an equal slice of strings to turn in to vars. (Except the
181 // last thread may get fewer if kNumStrings is not evenly divisible by
182 // kNumThreads).
183 for (size_t slice_start= 0; slice_start < kNumStrings;
184 slice_start += strings_per_thread) {
185 create_var_delegates.push_back(
186 CreateVarThreadDelegate(pp_module(),
187 &test_strings_[slice_start],
188 &vars_[slice_start],
189 &strings_out[slice_start],
190 std::min(strings_per_thread,
191 kNumStrings - slice_start)));
192 }
193 // Now run then join all the threads.
194 for (size_t i = 0; i < kNumThreads; ++i)
195 base::PlatformThread::Create(0, &create_var_delegates[i],
196 &create_var_threads[i]);
197 for (size_t i = 0; i < kNumThreads; ++i)
198 base::PlatformThread::Join(create_var_threads[i]);
199 // Now check that the strings have the expected values.
200 EXPECT_EQ(test_strings_, strings_out);
201
202 // Tinker with the reference counts in a multithreaded way.
203 std::vector<base::PlatformThreadHandle> change_ref_var_threads(kNumThreads);
204 std::vector<ChangeRefVarThreadDelegate> change_ref_var_delegates;
205 for (size_t i = 0; i < kNumThreads; ++i)
206 change_ref_var_delegates.push_back(ChangeRefVarThreadDelegate(vars_));
207 for (size_t i = 0; i < kNumThreads; ++i) {
208 base::PlatformThread::Create(0, &change_ref_var_delegates[i],
209 &change_ref_var_threads[i]);
210 }
211 for (size_t i = 0; i < kNumThreads; ++i)
212 base::PlatformThread::Join(change_ref_var_threads[i]);
213
214 // Now each var has a refcount of (kNumThreads + 1). Let's decrement each var
215 // once so that every 'RemoveRef' thread (spawned below) owns 1 reference, and
216 // when the last one removes a ref, the Var will be deleted.
217 for (size_t i = 0; i < kNumStrings; ++i) {
218 ppb_var_->Release(vars_[i]);
219 }
220
221 // Check that all vars are still valid and have the values we expect.
222 for (size_t i = 0; i < kNumStrings; ++i)
223 EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_));
224
225 // Remove the last reference counts for all vars.
226 std::vector<base::PlatformThreadHandle> remove_ref_var_threads(kNumThreads);
227 std::vector<RemoveRefVarThreadDelegate> remove_ref_var_delegates;
228 for (size_t i = 0; i < kNumThreads; ++i)
229 remove_ref_var_delegates.push_back(RemoveRefVarThreadDelegate(vars_));
230 for (size_t i = 0; i < kNumThreads; ++i) {
231 base::PlatformThread::Create(0, &remove_ref_var_delegates[i],
232 &remove_ref_var_threads[i]);
233 }
234 for (size_t i = 0; i < kNumThreads; ++i)
235 base::PlatformThread::Join(remove_ref_var_threads[i]);
236
237 // All the vars should no longer represent valid strings.
238 for (size_t i = 0; i < kNumStrings; ++i) {
239 uint32_t len = 10;
240 const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len);
241 EXPECT_EQ(NULL, utf8);
242 EXPECT_EQ(0u, len);
243 }
73 } 244 }
74 245
75 } // namespace proxy 246 } // namespace proxy
76 } // namespace ppapi 247 } // namespace ppapi
77 248
OLDNEW
« no previous file with comments | « ppapi/proxy/ppb_var_proxy.cc ('k') | ppapi/shared_impl/proxy_lock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698