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 3 // found in the LICENSE file. 4 5 #include "base/basictypes.h" 6 #include "base/mac/scoped_nsautorelease_pool.h" 7 #include "base/memory/scoped_ptr.h" 8 #include "base/shared_memory.h" 9 #include "base/test/multiprocess_test.h" 10 #include "base/threading/platform_thread.h" 11 #include "base/time.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/multiprocess_func_list.h" 14 15 static const int kNumThreads = 5; 16 static const int kNumTasks = 5; 17 18 namespace base { 19 20 namespace { 21 22 // Each thread will open the shared memory. Each thread will take a different 4 23 // byte int pointer, and keep changing it, with some small pauses in between. 24 // Verify that each thread's value in the shared memory is always correct. 25 class MultipleThreadMain : public PlatformThread::Delegate { 26 public: 27 explicit MultipleThreadMain(int16 id) : id_(id) {} 28 ~MultipleThreadMain() {} 29 30 static void CleanUp() { 31 SharedMemory memory; 32 memory.Delete(s_test_name_); 33 } 34 35 // PlatformThread::Delegate interface. 36 void ThreadMain() { 37 mac::ScopedNSAutoreleasePool pool; // noop if not OSX 38 const uint32 kDataSize = 1024; 39 SharedMemory memory; 40 bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); 41 EXPECT_TRUE(rv); 42 rv = memory.Map(kDataSize); 43 EXPECT_TRUE(rv); 44 int *ptr = static_cast<int*>(memory.memory()) + id_; 45 EXPECT_EQ(*ptr, 0); 46 47 for (int idx = 0; idx < 100; idx++) { 48 *ptr = idx; 49 PlatformThread::Sleep(1); // Short wait. 50 EXPECT_EQ(*ptr, idx); 51 } 52 53 memory.Close(); 54 } 55 56 private: 57 int16 id_; 58 59 static const char* const s_test_name_; 60 61 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); 62 }; 63 64 const char* const MultipleThreadMain::s_test_name_ = 65 "SharedMemoryOpenThreadTest"; 66 67 // TODO(port): 68 // This test requires the ability to pass file descriptors between processes. 69 // We haven't done that yet in Chrome for POSIX. 70 #if defined(OS_WIN) 71 // Each thread will open the shared memory. Each thread will take the memory, 72 // and keep changing it while trying to lock it, with some small pauses in 73 // between. Verify that each thread's value in the shared memory is always 74 // correct. 75 class MultipleLockThread : public PlatformThread::Delegate { 76 public: 77 explicit MultipleLockThread(int id) : id_(id) {} 78 ~MultipleLockThread() {} 79 80 // PlatformThread::Delegate interface. 81 void ThreadMain() { 82 const uint32 kDataSize = sizeof(int); 83 SharedMemoryHandle handle = NULL; 84 { 85 SharedMemory memory1; 86 EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest", 87 true, kDataSize)); 88 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); 89 // TODO(paulg): Implement this once we have a posix version of 90 // SharedMemory::ShareToProcess. 91 EXPECT_TRUE(true); 92 } 93 94 SharedMemory memory2(handle, false); 95 EXPECT_TRUE(memory2.Map(kDataSize)); 96 volatile int* const ptr = static_cast<int*>(memory2.memory()); 97 98 for (int idx = 0; idx < 20; idx++) { 99 memory2.Lock(); 100 int i = (id_ << 16) + idx; 101 *ptr = i; 102 PlatformThread::Sleep(1); // Short wait. 103 EXPECT_EQ(*ptr, i); 104 memory2.Unlock(); 105 } 106 107 memory2.Close(); 108 } 109 110 private: 111 int id_; 112 113 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); 114 }; 115 #endif 116 117 } // namespace 118 119 TEST(SharedMemoryTest, OpenClose) { 120 const uint32 kDataSize = 1024; 121 std::string test_name = "SharedMemoryOpenCloseTest"; 122 123 // Open two handles to a memory segment, confirm that they are mapped 124 // separately yet point to the same space. 125 SharedMemory memory1; 126 bool rv = memory1.Delete(test_name); 127 EXPECT_TRUE(rv); 128 rv = memory1.Delete(test_name); 129 EXPECT_TRUE(rv); 130 rv = memory1.Open(test_name, false); 131 EXPECT_FALSE(rv); 132 rv = memory1.CreateNamed(test_name, false, kDataSize); 133 EXPECT_TRUE(rv); 134 rv = memory1.Map(kDataSize); 135 EXPECT_TRUE(rv); 136 SharedMemory memory2; 137 rv = memory2.Open(test_name, false); 138 EXPECT_TRUE(rv); 139 rv = memory2.Map(kDataSize); 140 EXPECT_TRUE(rv); 141 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. 142 143 // Make sure we don't segfault. (it actually happened!) 144 ASSERT_NE(memory1.memory(), static_cast<void*>(NULL)); 145 ASSERT_NE(memory2.memory(), static_cast<void*>(NULL)); 146 147 // Write data to the first memory segment, verify contents of second. 148 memset(memory1.memory(), '1', kDataSize); 149 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); 150 151 // Close the first memory segment, and verify the second has the right data. 152 memory1.Close(); 153 char *start_ptr = static_cast<char *>(memory2.memory()); 154 char *end_ptr = start_ptr + kDataSize; 155 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) 156 EXPECT_EQ(*ptr, '1'); 157 158 // Close the second memory segment. 159 memory2.Close(); 160 161 rv = memory1.Delete(test_name); 162 EXPECT_TRUE(rv); 163 rv = memory2.Delete(test_name); 164 EXPECT_TRUE(rv); 165 } 166 167 TEST(SharedMemoryTest, OpenExclusive) { 168 const uint32 kDataSize = 1024; 169 const uint32 kDataSize2 = 2048; 170 std::ostringstream test_name_stream; 171 test_name_stream << "SharedMemoryOpenExclusiveTest." 172 << Time::Now().ToDoubleT(); 173 std::string test_name = test_name_stream.str(); 174 175 // Open two handles to a memory segment and check that open_existing works 176 // as expected. 177 SharedMemory memory1; 178 bool rv = memory1.CreateNamed(test_name, false, kDataSize); 179 EXPECT_TRUE(rv); 180 181 // Memory1 knows it's size because it created it. 182 EXPECT_EQ(memory1.created_size(), kDataSize); 183 184 rv = memory1.Map(kDataSize); 185 EXPECT_TRUE(rv); 186 187 memset(memory1.memory(), 'G', kDataSize); 188 189 SharedMemory memory2; 190 // Should not be able to create if openExisting is false. 191 rv = memory2.CreateNamed(test_name, false, kDataSize2); 192 EXPECT_FALSE(rv); 193 194 // Should be able to create with openExisting true. 195 rv = memory2.CreateNamed(test_name, true, kDataSize2); 196 EXPECT_TRUE(rv); 197 198 // Memory2 shouldn't know the size because we didn't create it. 199 EXPECT_EQ(memory2.created_size(), 0U); 200 201 // We should be able to map the original size. 202 rv = memory2.Map(kDataSize); 203 EXPECT_TRUE(rv); 204 205 // Verify that opening memory2 didn't truncate or delete memory 1. 206 char *start_ptr = static_cast<char *>(memory2.memory()); 207 char *end_ptr = start_ptr + kDataSize; 208 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { 209 EXPECT_EQ(*ptr, 'G'); 210 } 211 212 memory1.Close(); 213 memory2.Close(); 214 215 rv = memory1.Delete(test_name); 216 EXPECT_TRUE(rv); 217 } 218 219 // Create a set of N threads to each open a shared memory segment and write to 220 // it. Verify that they are always reading/writing consistent data. 221 TEST(SharedMemoryTest, MultipleThreads) { 222 MultipleThreadMain::CleanUp(); 223 // On POSIX we have a problem when 2 threads try to create the shmem 224 // (a file) at exactly the same time, since create both creates the 225 // file and zerofills it. We solve the problem for this unit test 226 // (make it not flaky) by starting with 1 thread, then 227 // intentionally don't clean up its shmem before running with 228 // kNumThreads. 229 230 int threadcounts[] = { 1, kNumThreads }; 231 for (size_t i = 0; i < sizeof(threadcounts) / sizeof(threadcounts); i++) { 232 int numthreads = threadcounts[i]; 233 scoped_array<PlatformThreadHandle> thread_handles; 234 scoped_array<MultipleThreadMain*> thread_delegates; 235 236 thread_handles.reset(new PlatformThreadHandle[numthreads]); 237 thread_delegates.reset(new MultipleThreadMain*[numthreads]); 238 239 // Spawn the threads. 240 for (int16 index = 0; index < numthreads; index++) { 241 PlatformThreadHandle pth; 242 thread_delegates[index] = new MultipleThreadMain(index); 243 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); 244 thread_handles[index] = pth; 245 } 246 247 // Wait for the threads to finish. 248 for (int index = 0; index < numthreads; index++) { 249 PlatformThread::Join(thread_handles[index]); 250 delete thread_delegates[index]; 251 } 252 } 253 MultipleThreadMain::CleanUp(); 254 } 255 256 // TODO(port): this test requires the MultipleLockThread class 257 // (defined above), which requires the ability to pass file 258 // descriptors between processes. We haven't done that yet in Chrome 259 // for POSIX. 260 #if defined(OS_WIN) 261 // Create a set of threads to each open a shared memory segment and write to it 262 // with the lock held. Verify that they are always reading/writing consistent 263 // data. 264 TEST(SharedMemoryTest, Lock) { 265 PlatformThreadHandle thread_handles[kNumThreads]; 266 MultipleLockThread* thread_delegates[kNumThreads]; 267 268 // Spawn the threads. 269 for (int index = 0; index < kNumThreads; ++index) { 270 PlatformThreadHandle pth; 271 thread_delegates[index] = new MultipleLockThread(index); 272 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); 273 thread_handles[index] = pth; 274 } 275 276 // Wait for the threads to finish. 277 for (int index = 0; index < kNumThreads; ++index) { 278 PlatformThread::Join(thread_handles[index]); 279 delete thread_delegates[index]; 280 } 281 } 282 #endif 283 284 // Allocate private (unique) shared memory with an empty string for a 285 // name. Make sure several of them don't point to the same thing as 286 // we might expect if the names are equal. 287 TEST(SharedMemoryTest, AnonymousPrivate) { 288 int i, j; 289 int count = 4; 290 bool rv; 291 const uint32 kDataSize = 8192; 292 293 scoped_array<SharedMemory> memories(new SharedMemory[count]); 294 scoped_array<int*> pointers(new int*[count]); 295 ASSERT_TRUE(memories.get()); 296 ASSERT_TRUE(pointers.get()); 297 298 for (i = 0; i < count; i++) { 299 rv = memories[i].CreateAndMapAnonymous(kDataSize); 300 EXPECT_TRUE(rv); 301 int *ptr = static_cast<int*>(memories[i].memory()); 302 EXPECT_TRUE(ptr); 303 pointers[i] = ptr; 304 } 305 306 for (i = 0; i < count; i++) { 307 // zero out the first int in each except for i; for that one, make it 100. 308 for (j = 0; j < count; j++) { 309 if (i == j) 310 pointers[j][0] = 100; 311 else 312 pointers[j][0] = 0; 313 } 314 // make sure there is no bleeding of the 100 into the other pointers 315 for (j = 0; j < count; j++) { 316 if (i == j) 317 EXPECT_EQ(100, pointers[j][0]); 318 else 319 EXPECT_EQ(0, pointers[j][0]); 320 } 321 } 322 323 for (int i = 0; i < count; i++) { 324 memories[i].Close(); 325 } 326 } 327 328 // On POSIX it is especially important we test shmem across processes, 329 // not just across threads. But the test is enabled on all platforms. 330 class SharedMemoryProcessTest : public MultiProcessTest { 331 public: 332 333 static void CleanUp() { 334 SharedMemory memory; 335 memory.Delete(s_test_name_); 336 } 337 338 static int TaskTestMain() { 339 int errors = 0; 340 mac::ScopedNSAutoreleasePool pool; // noop if not OSX 341 const uint32 kDataSize = 1024; 342 SharedMemory memory; 343 bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); 344 EXPECT_TRUE(rv); 345 if (rv != true) 346 errors++; 347 rv = memory.Map(kDataSize); 348 EXPECT_TRUE(rv); 349 if (rv != true) 350 errors++; 351 int *ptr = static_cast<int*>(memory.memory()); 352 353 for (int idx = 0; idx < 20; idx++) { 354 memory.Lock(); 355 int i = (1 << 16) + idx; 356 *ptr = i; 357 PlatformThread::Sleep(10); // Short wait. 358 if (*ptr != i) 359 errors++; 360 memory.Unlock(); 361 } 362 363 memory.Close(); 364 return errors; 365 } 366 367 private: 368 static const char* const s_test_name_; 369 }; 370 371 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; 372 373 374 #if defined(OS_MACOSX) 375 #define MAYBE_Tasks FLAKY_Tasks 376 #else 377 #define MAYBE_Tasks Tasks 378 #endif 379 380 TEST_F(SharedMemoryProcessTest, MAYBE_Tasks) { 381 SharedMemoryProcessTest::CleanUp(); 382 383 ProcessHandle handles[kNumTasks]; 384 for (int index = 0; index < kNumTasks; ++index) { 385 handles[index] = SpawnChild("SharedMemoryTestMain", false); 386 } 387 388 int exit_code = 0; 389 for (int index = 0; index < kNumTasks; ++index) { 390 EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code)); 391 EXPECT_TRUE(exit_code == 0); 392 } 393 394 SharedMemoryProcessTest::CleanUp(); 395 } 396 397 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { 398 return SharedMemoryProcessTest::TaskTestMain(); 399 } 400 401 } // namespace base 402