OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium 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 "base/memory/shared_memory_allocator.h" | |
6 | |
7 #include "base/memory/scoped_ptr.h" | |
8 #include "base/rand_util.h" | |
9 #include "base/threading/simple_thread.h" | |
10 #include "testing/gmock/include/gmock/gmock.h" | |
11 | |
12 namespace { | |
13 | |
14 const int32_t TEST_MEMORY_SIZE = 1 << 20; // 1 MiB | |
15 const int32_t TEST_MEMORY_PAGE = 64 << 10; // 64 KiB | |
16 | |
17 } // namespace | |
18 | |
19 namespace base { | |
20 | |
21 class SharedMemoryAllocatorTest : public testing::Test { | |
22 public: | |
23 struct TestObject1 { | |
24 int32_t onething; | |
25 char oranother; | |
26 }; | |
27 | |
28 struct TestObject2 { | |
29 int thiis; | |
30 long that; | |
31 float andthe; | |
32 char other; | |
33 double thing; | |
34 }; | |
35 | |
36 SharedMemoryAllocatorTest() { | |
37 mem_segment_.reset(new char[TEST_MEMORY_SIZE]); | |
38 } | |
39 | |
40 void SetUp() override { | |
41 allocator_.reset(); | |
42 memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); | |
43 allocator_.reset(new SharedMemoryAllocator(mem_segment_.get(), | |
44 TEST_MEMORY_SIZE, | |
45 TEST_MEMORY_PAGE)); | |
46 } | |
47 | |
48 void TearDown() override { | |
49 allocator_.reset(); | |
50 } | |
51 | |
52 int CountIterables() { | |
53 SharedMemoryAllocator::Iterator iter; | |
54 int32_t type; | |
55 int count = 0; | |
56 for (allocator_->CreateIterator(&iter); | |
57 allocator_->GetNextIterable(&iter, &type) != 0;) { | |
58 count++; | |
59 } | |
60 return count; | |
61 } | |
62 | |
63 scoped_ptr<char[]> mem_segment_; | |
64 scoped_ptr<SharedMemoryAllocator> allocator_; | |
65 }; | |
66 | |
67 TEST_F(SharedMemoryAllocatorTest, AllocateAndIterate) { | |
68 SharedMemoryAllocator::MemoryInfo meminfo0; | |
69 allocator_->GetMemoryInfo(&meminfo0); | |
70 EXPECT_EQ(TEST_MEMORY_SIZE, meminfo0.total); | |
71 EXPECT_GT(meminfo0.total, meminfo0.free); | |
72 | |
73 int32_t block1 = allocator_->Allocate(sizeof(TestObject1), 1); | |
74 EXPECT_NE(0, block1); | |
75 EXPECT_NE(nullptr, allocator_->GetType<TestObject1>(block1, 1)); | |
76 EXPECT_EQ(nullptr, allocator_->GetType<TestObject2>(block1, 1)); | |
77 SharedMemoryAllocator::MemoryInfo meminfo1; | |
78 allocator_->GetMemoryInfo(&meminfo1); | |
79 EXPECT_EQ(meminfo0.total, meminfo1.total); | |
80 EXPECT_GT(meminfo0.free, meminfo1.free); | |
81 | |
82 SharedMemoryAllocator::Iterator iter; | |
83 int32_t type; | |
84 allocator_->CreateIterator(&iter); | |
85 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
86 allocator_->MakeIterable(block1); | |
87 EXPECT_EQ(block1, allocator_->GetNextIterable(&iter, &type)); | |
88 EXPECT_EQ(1, type); | |
89 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
90 | |
91 int32_t block2 = allocator_->Allocate(sizeof(TestObject2), 2); | |
92 EXPECT_NE(0, block2); | |
93 EXPECT_NE(nullptr, allocator_->GetType<TestObject2>(block2, 2)); | |
94 EXPECT_EQ(nullptr, allocator_->GetType<TestObject2>(block2, 1)); | |
95 SharedMemoryAllocator::MemoryInfo meminfo2; | |
96 allocator_->GetMemoryInfo(&meminfo2); | |
97 EXPECT_EQ(meminfo1.total, meminfo2.total); | |
98 EXPECT_GT(meminfo1.free, meminfo2.free); | |
99 | |
100 allocator_->MakeIterable(block2); | |
101 EXPECT_EQ(block2, allocator_->GetNextIterable(&iter, &type)); | |
102 EXPECT_EQ(2, type); | |
103 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
104 | |
105 EXPECT_FALSE(allocator_->IsFull()); | |
106 EXPECT_FALSE(allocator_->IsCorrupted()); | |
107 } | |
108 | |
109 TEST_F(SharedMemoryAllocatorTest, PageTest) { | |
110 int32_t block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1); | |
111 EXPECT_LT(0, block1); | |
112 EXPECT_GT(TEST_MEMORY_PAGE, block1); | |
113 | |
114 int32_t block2 = allocator_->Allocate(TEST_MEMORY_PAGE - 16, 2); | |
115 EXPECT_EQ(TEST_MEMORY_PAGE, block2); | |
116 | |
117 int32_t block3 = allocator_->Allocate(99, 3); | |
118 EXPECT_EQ(2 * TEST_MEMORY_PAGE, block3); | |
119 } | |
120 | |
121 class AllocatorThread : public SimpleThread { | |
122 public: | |
123 AllocatorThread(const std::string& name, void* base, int32_t size, | |
124 int32_t page_size) | |
125 : SimpleThread(name, Options()), | |
126 count_(0), | |
127 iterable_(0), | |
128 allocator_(base, size, page_size) { | |
129 } | |
130 | |
131 void Run() override { | |
132 for (;;) { | |
133 int32_t size = (int32_t)base::RandInt(1, 99); | |
134 int32_t type = (int32_t)base::RandInt(100, 999); | |
135 int32_t block = allocator_.Allocate(size, type); | |
136 if (!block) | |
137 break; | |
138 | |
139 count_++; | |
140 if (base::RandInt(0, 1)) { | |
141 allocator_.MakeIterable(block); | |
142 iterable_++; | |
143 } | |
144 } | |
145 } | |
146 | |
147 int count_; | |
148 int iterable_; | |
149 | |
150 private: | |
151 SharedMemoryAllocator allocator_; | |
152 }; | |
153 | |
154 TEST_F(SharedMemoryAllocatorTest, ParallelismTest) { | |
155 void* memory = mem_segment_.get(); | |
156 AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
157 AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
158 AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
159 AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
160 AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
Dmitry Vyukov
2015/11/03 14:06:46
Also run iteration thread concurrently.
bcwhite
2015/11/03 16:28:20
The test thread is doing that concurrently with th
| |
161 | |
162 t1.Start(); | |
163 t2.Start(); | |
164 t3.Start(); | |
165 t4.Start(); | |
166 t5.Start(); | |
167 | |
168 int last_count = 0; | |
169 do { | |
170 int count = CountIterables(); | |
171 EXPECT_LE(last_count, count); | |
172 } while (!allocator_->IsCorrupted() && !allocator_->IsFull()); | |
173 | |
174 t1.Join(); | |
175 t2.Join(); | |
176 t3.Join(); | |
177 t4.Join(); | |
178 t5.Join(); | |
179 | |
180 EXPECT_FALSE(allocator_->IsCorrupted()); | |
181 EXPECT_EQ(CountIterables(), | |
182 t1.iterable_ + t2.iterable_ + t3.iterable_ + t4.iterable_ + | |
183 t5.iterable_); | |
184 } | |
185 | |
186 // This test doesn't verify anything other than it doesn't crash. | |
187 TEST_F(SharedMemoryAllocatorTest, CorruptionTest) { | |
188 char* memory = mem_segment_.get(); | |
189 AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
190 AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
191 AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
192 AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
193 AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
Dmitry Vyukov
2015/11/03 14:06:46
Also run iteration thread concurrently.
| |
194 | |
195 t1.Start(); | |
196 t2.Start(); | |
197 t3.Start(); | |
198 t4.Start(); | |
199 t5.Start(); | |
200 | |
201 do { | |
202 size_t offset = base::RandInt(0, TEST_MEMORY_SIZE - 1); | |
203 char value = base::RandInt(0, 255); | |
204 memory[offset] = value; | |
205 } while (!allocator_->IsCorrupted() && !allocator_->IsFull()); | |
206 | |
207 t1.Join(); | |
208 t2.Join(); | |
209 t3.Join(); | |
210 t4.Join(); | |
211 t5.Join(); | |
212 | |
213 CountIterables(); | |
214 } | |
215 | |
216 // Attempt to cause crashes or loops by expressly creating dangerous coditions. | |
217 TEST_F(SharedMemoryAllocatorTest, MaliciousTest) { | |
218 int32_t block1 = allocator_->Allocate(sizeof(TestObject1), 1); | |
219 int32_t block2 = allocator_->Allocate(sizeof(TestObject1), 2); | |
220 int32_t block3 = allocator_->Allocate(sizeof(TestObject1), 3); | |
221 int32_t block4 = allocator_->Allocate(sizeof(TestObject1), 3); | |
222 int32_t block5 = allocator_->Allocate(sizeof(TestObject1), 3); | |
223 allocator_->MakeIterable(block1); | |
224 allocator_->MakeIterable(block2); | |
225 allocator_->MakeIterable(block3); | |
226 allocator_->MakeIterable(block4); | |
227 allocator_->MakeIterable(block5); | |
228 EXPECT_EQ(5, CountIterables()); | |
229 EXPECT_FALSE(allocator_->IsCorrupted()); | |
230 | |
231 // Create loop in iterable list and ensure it doesn't hang. | |
232 int32_t* header4 = (int32_t*)(mem_segment_.get() + block4); | |
233 EXPECT_EQ(block5, header4[3]); | |
234 header4[3] = block3; | |
235 CountIterables(); // loop: 1-2-3-4-3 | |
236 header4[3] = block2; | |
237 CountIterables(); // loop: 1-2-3-4-2 | |
238 header4[3] = block1; | |
239 CountIterables(); // loop: 1-2-3-4-1 | |
240 EXPECT_TRUE(allocator_->IsCorrupted()); | |
241 } | |
242 | |
243 } // namespace base | |
OLD | NEW |