shared_memory_unittest.cc revision 58e6fbe4ee35d65e14b626c557d37565bf8ad179
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 3// found in the LICENSE file. 4 5#include "base/basictypes.h" 6#include "base/memory/scoped_ptr.h" 7#include "base/memory/shared_memory.h" 8#include "base/process/kill.h" 9#include "base/rand_util.h" 10#include "base/strings/string_number_conversions.h" 11#include "base/sys_info.h" 12#include "base/test/multiprocess_test.h" 13#include "base/threading/platform_thread.h" 14#include "base/time/time.h" 15#include "testing/gtest/include/gtest/gtest.h" 16#include "testing/multiprocess_func_list.h" 17 18#if defined(OS_MACOSX) 19#include "base/mac/scoped_nsautorelease_pool.h" 20#endif 21 22#if defined(OS_POSIX) 23#include <sys/mman.h> 24#include <sys/stat.h> 25#include <sys/types.h> 26#include <unistd.h> 27#endif 28 29static const int kNumThreads = 5; 30static const int kNumTasks = 5; 31 32namespace base { 33 34namespace { 35 36// Each thread will open the shared memory. Each thread will take a different 4 37// byte int pointer, and keep changing it, with some small pauses in between. 38// Verify that each thread's value in the shared memory is always correct. 39class MultipleThreadMain : public PlatformThread::Delegate { 40 public: 41 explicit MultipleThreadMain(int16 id) : id_(id) {} 42 virtual ~MultipleThreadMain() {} 43 44 static void CleanUp() { 45 SharedMemory memory; 46 memory.Delete(s_test_name_); 47 } 48 49 // PlatformThread::Delegate interface. 50 virtual void ThreadMain() OVERRIDE { 51#if defined(OS_MACOSX) 52 mac::ScopedNSAutoreleasePool pool; 53#endif 54 const uint32 kDataSize = 1024; 55 SharedMemory memory; 56 bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); 57 EXPECT_TRUE(rv); 58 rv = memory.Map(kDataSize); 59 EXPECT_TRUE(rv); 60 int *ptr = static_cast<int*>(memory.memory()) + id_; 61 EXPECT_EQ(0, *ptr); 62 63 for (int idx = 0; idx < 100; idx++) { 64 *ptr = idx; 65 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); 66 EXPECT_EQ(*ptr, idx); 67 } 68 // Reset back to 0 for the next test that uses the same name. 69 *ptr = 0; 70 71 memory.Close(); 72 } 73 74 private: 75 int16 id_; 76 77 static const char* const s_test_name_; 78 79 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); 80}; 81 82const char* const MultipleThreadMain::s_test_name_ = 83 "SharedMemoryOpenThreadTest"; 84 85// TODO(port): 86// This test requires the ability to pass file descriptors between processes. 87// We haven't done that yet in Chrome for POSIX. 88#if defined(OS_WIN) 89// Each thread will open the shared memory. Each thread will take the memory, 90// and keep changing it while trying to lock it, with some small pauses in 91// between. Verify that each thread's value in the shared memory is always 92// correct. 93class MultipleLockThread : public PlatformThread::Delegate { 94 public: 95 explicit MultipleLockThread(int id) : id_(id) {} 96 virtual ~MultipleLockThread() {} 97 98 // PlatformThread::Delegate interface. 99 virtual void ThreadMain() OVERRIDE { 100 const uint32 kDataSize = sizeof(int); 101 SharedMemoryHandle handle = NULL; 102 { 103 SharedMemory memory1; 104 EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest", 105 true, kDataSize)); 106 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); 107 // TODO(paulg): Implement this once we have a posix version of 108 // SharedMemory::ShareToProcess. 109 EXPECT_TRUE(true); 110 } 111 112 SharedMemory memory2(handle, false); 113 EXPECT_TRUE(memory2.Map(kDataSize)); 114 volatile int* const ptr = static_cast<int*>(memory2.memory()); 115 116 for (int idx = 0; idx < 20; idx++) { 117 memory2.Lock(); 118 int i = (id_ << 16) + idx; 119 *ptr = i; 120 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); 121 EXPECT_EQ(*ptr, i); 122 memory2.Unlock(); 123 } 124 125 memory2.Close(); 126 } 127 128 private: 129 int id_; 130 131 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); 132}; 133#endif 134 135} // namespace 136 137// Android doesn't support SharedMemory::Open/Delete/ 138// CreateNamed(openExisting=true) 139#if !defined(OS_ANDROID) 140TEST(SharedMemoryTest, OpenClose) { 141 const uint32 kDataSize = 1024; 142 std::string test_name = "SharedMemoryOpenCloseTest"; 143 144 // Open two handles to a memory segment, confirm that they are mapped 145 // separately yet point to the same space. 146 SharedMemory memory1; 147 bool rv = memory1.Delete(test_name); 148 EXPECT_TRUE(rv); 149 rv = memory1.Delete(test_name); 150 EXPECT_TRUE(rv); 151 rv = memory1.Open(test_name, false); 152 EXPECT_FALSE(rv); 153 rv = memory1.CreateNamed(test_name, false, kDataSize); 154 EXPECT_TRUE(rv); 155 rv = memory1.Map(kDataSize); 156 EXPECT_TRUE(rv); 157 SharedMemory memory2; 158 rv = memory2.Open(test_name, false); 159 EXPECT_TRUE(rv); 160 rv = memory2.Map(kDataSize); 161 EXPECT_TRUE(rv); 162 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. 163 164 // Make sure we don't segfault. (it actually happened!) 165 ASSERT_NE(memory1.memory(), static_cast<void*>(NULL)); 166 ASSERT_NE(memory2.memory(), static_cast<void*>(NULL)); 167 168 // Write data to the first memory segment, verify contents of second. 169 memset(memory1.memory(), '1', kDataSize); 170 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); 171 172 // Close the first memory segment, and verify the second has the right data. 173 memory1.Close(); 174 char *start_ptr = static_cast<char *>(memory2.memory()); 175 char *end_ptr = start_ptr + kDataSize; 176 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) 177 EXPECT_EQ(*ptr, '1'); 178 179 // Close the second memory segment. 180 memory2.Close(); 181 182 rv = memory1.Delete(test_name); 183 EXPECT_TRUE(rv); 184 rv = memory2.Delete(test_name); 185 EXPECT_TRUE(rv); 186} 187 188TEST(SharedMemoryTest, OpenExclusive) { 189 const uint32 kDataSize = 1024; 190 const uint32 kDataSize2 = 2048; 191 std::ostringstream test_name_stream; 192 test_name_stream << "SharedMemoryOpenExclusiveTest." 193 << Time::Now().ToDoubleT(); 194 std::string test_name = test_name_stream.str(); 195 196 // Open two handles to a memory segment and check that open_existing works 197 // as expected. 198 SharedMemory memory1; 199 bool rv = memory1.CreateNamed(test_name, false, kDataSize); 200 EXPECT_TRUE(rv); 201 202 // Memory1 knows it's size because it created it. 203 EXPECT_EQ(memory1.requested_size(), kDataSize); 204 205 rv = memory1.Map(kDataSize); 206 EXPECT_TRUE(rv); 207 208 // The mapped memory1 must be at least the size we asked for. 209 EXPECT_GE(memory1.mapped_size(), kDataSize); 210 211 // The mapped memory1 shouldn't exceed rounding for allocation granularity. 212 EXPECT_LT(memory1.mapped_size(), 213 kDataSize + base::SysInfo::VMAllocationGranularity()); 214 215 memset(memory1.memory(), 'G', kDataSize); 216 217 SharedMemory memory2; 218 // Should not be able to create if openExisting is false. 219 rv = memory2.CreateNamed(test_name, false, kDataSize2); 220 EXPECT_FALSE(rv); 221 222 // Should be able to create with openExisting true. 223 rv = memory2.CreateNamed(test_name, true, kDataSize2); 224 EXPECT_TRUE(rv); 225 226 // Memory2 shouldn't know the size because we didn't create it. 227 EXPECT_EQ(memory2.requested_size(), 0U); 228 229 // We should be able to map the original size. 230 rv = memory2.Map(kDataSize); 231 EXPECT_TRUE(rv); 232 233 // The mapped memory2 must be at least the size of the original. 234 EXPECT_GE(memory2.mapped_size(), kDataSize); 235 236 // The mapped memory2 shouldn't exceed rounding for allocation granularity. 237 EXPECT_LT(memory2.mapped_size(), 238 kDataSize2 + base::SysInfo::VMAllocationGranularity()); 239 240 // Verify that opening memory2 didn't truncate or delete memory 1. 241 char *start_ptr = static_cast<char *>(memory2.memory()); 242 char *end_ptr = start_ptr + kDataSize; 243 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { 244 EXPECT_EQ(*ptr, 'G'); 245 } 246 247 memory1.Close(); 248 memory2.Close(); 249 250 rv = memory1.Delete(test_name); 251 EXPECT_TRUE(rv); 252} 253#endif 254 255// Create a set of N threads to each open a shared memory segment and write to 256// it. Verify that they are always reading/writing consistent data. 257TEST(SharedMemoryTest, MultipleThreads) { 258 MultipleThreadMain::CleanUp(); 259 // On POSIX we have a problem when 2 threads try to create the shmem 260 // (a file) at exactly the same time, since create both creates the 261 // file and zerofills it. We solve the problem for this unit test 262 // (make it not flaky) by starting with 1 thread, then 263 // intentionally don't clean up its shmem before running with 264 // kNumThreads. 265 266 int threadcounts[] = { 1, kNumThreads }; 267 for (size_t i = 0; i < arraysize(threadcounts); i++) { 268 int numthreads = threadcounts[i]; 269 scoped_ptr<PlatformThreadHandle[]> thread_handles; 270 scoped_ptr<MultipleThreadMain*[]> thread_delegates; 271 272 thread_handles.reset(new PlatformThreadHandle[numthreads]); 273 thread_delegates.reset(new MultipleThreadMain*[numthreads]); 274 275 // Spawn the threads. 276 for (int16 index = 0; index < numthreads; index++) { 277 PlatformThreadHandle pth; 278 thread_delegates[index] = new MultipleThreadMain(index); 279 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); 280 thread_handles[index] = pth; 281 } 282 283 // Wait for the threads to finish. 284 for (int index = 0; index < numthreads; index++) { 285 PlatformThread::Join(thread_handles[index]); 286 delete thread_delegates[index]; 287 } 288 } 289 MultipleThreadMain::CleanUp(); 290} 291 292// TODO(port): this test requires the MultipleLockThread class 293// (defined above), which requires the ability to pass file 294// descriptors between processes. We haven't done that yet in Chrome 295// for POSIX. 296#if defined(OS_WIN) 297// Create a set of threads to each open a shared memory segment and write to it 298// with the lock held. Verify that they are always reading/writing consistent 299// data. 300TEST(SharedMemoryTest, Lock) { 301 PlatformThreadHandle thread_handles[kNumThreads]; 302 MultipleLockThread* thread_delegates[kNumThreads]; 303 304 // Spawn the threads. 305 for (int index = 0; index < kNumThreads; ++index) { 306 PlatformThreadHandle pth; 307 thread_delegates[index] = new MultipleLockThread(index); 308 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); 309 thread_handles[index] = pth; 310 } 311 312 // Wait for the threads to finish. 313 for (int index = 0; index < kNumThreads; ++index) { 314 PlatformThread::Join(thread_handles[index]); 315 delete thread_delegates[index]; 316 } 317} 318#endif 319 320// Allocate private (unique) shared memory with an empty string for a 321// name. Make sure several of them don't point to the same thing as 322// we might expect if the names are equal. 323TEST(SharedMemoryTest, AnonymousPrivate) { 324 int i, j; 325 int count = 4; 326 bool rv; 327 const uint32 kDataSize = 8192; 328 329 scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]); 330 scoped_ptr<int*[]> pointers(new int*[count]); 331 ASSERT_TRUE(memories.get()); 332 ASSERT_TRUE(pointers.get()); 333 334 for (i = 0; i < count; i++) { 335 rv = memories[i].CreateAndMapAnonymous(kDataSize); 336 EXPECT_TRUE(rv); 337 int *ptr = static_cast<int*>(memories[i].memory()); 338 EXPECT_TRUE(ptr); 339 pointers[i] = ptr; 340 } 341 342 for (i = 0; i < count; i++) { 343 // zero out the first int in each except for i; for that one, make it 100. 344 for (j = 0; j < count; j++) { 345 if (i == j) 346 pointers[j][0] = 100; 347 else 348 pointers[j][0] = 0; 349 } 350 // make sure there is no bleeding of the 100 into the other pointers 351 for (j = 0; j < count; j++) { 352 if (i == j) 353 EXPECT_EQ(100, pointers[j][0]); 354 else 355 EXPECT_EQ(0, pointers[j][0]); 356 } 357 } 358 359 for (int i = 0; i < count; i++) { 360 memories[i].Close(); 361 } 362} 363 364TEST(SharedMemoryTest, MapAt) { 365 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32)); 366 const size_t kCount = SysInfo::VMAllocationGranularity(); 367 const size_t kDataSize = kCount * sizeof(uint32); 368 369 SharedMemory memory; 370 ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); 371 ASSERT_TRUE(memory.Map(kDataSize)); 372 uint32* ptr = static_cast<uint32*>(memory.memory()); 373 ASSERT_NE(ptr, static_cast<void*>(NULL)); 374 375 for (size_t i = 0; i < kCount; ++i) { 376 ptr[i] = i; 377 } 378 379 memory.Unmap(); 380 381 off_t offset = SysInfo::VMAllocationGranularity(); 382 ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset)); 383 offset /= sizeof(uint32); 384 ptr = static_cast<uint32*>(memory.memory()); 385 ASSERT_NE(ptr, static_cast<void*>(NULL)); 386 for (size_t i = offset; i < kCount; ++i) { 387 EXPECT_EQ(ptr[i - offset], i); 388 } 389} 390 391#if defined(OS_POSIX) 392// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. 393TEST(SharedMemoryTest, AnonymousExecutable) { 394 const uint32 kTestSize = 1 << 16; 395 396 SharedMemory shared_memory; 397 SharedMemoryCreateOptions options; 398 options.size = kTestSize; 399 options.executable = true; 400 401 EXPECT_TRUE(shared_memory.Create(options)); 402 EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); 403 404 EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(), 405 PROT_READ | PROT_EXEC)); 406} 407 408// Android supports a different permission model than POSIX for its "ashmem" 409// shared memory implementation. So the tests about file permissions are not 410// included on Android. 411#if !defined(OS_ANDROID) 412 413// Set a umask and restore the old mask on destruction. 414class ScopedUmaskSetter { 415 public: 416 explicit ScopedUmaskSetter(mode_t target_mask) { 417 old_umask_ = umask(target_mask); 418 } 419 ~ScopedUmaskSetter() { umask(old_umask_); } 420 private: 421 mode_t old_umask_; 422 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); 423}; 424 425// Create a shared memory object, check its permissions. 426TEST(SharedMemoryTest, FilePermissionsAnonymous) { 427 const uint32 kTestSize = 1 << 8; 428 429 SharedMemory shared_memory; 430 SharedMemoryCreateOptions options; 431 options.size = kTestSize; 432 // Set a file mode creation mask that gives all permissions. 433 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); 434 435 EXPECT_TRUE(shared_memory.Create(options)); 436 437 int shm_fd = shared_memory.handle().fd; 438 struct stat shm_stat; 439 EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); 440 // Neither the group, nor others should be able to read the shared memory 441 // file. 442 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); 443 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); 444} 445 446// Create a shared memory object, check its permissions. 447TEST(SharedMemoryTest, FilePermissionsNamed) { 448 const uint32 kTestSize = 1 << 8; 449 450 SharedMemory shared_memory; 451 SharedMemoryCreateOptions options; 452 options.size = kTestSize; 453 std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) + 454 "-" + Uint64ToString(RandUint64()); 455 options.name = &shared_mem_name; 456 // Set a file mode creation mask that gives all permissions. 457 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); 458 459 EXPECT_TRUE(shared_memory.Create(options)); 460 // Clean-up the backing file name immediately, we don't need it. 461 EXPECT_TRUE(shared_memory.Delete(shared_mem_name)); 462 463 int shm_fd = shared_memory.handle().fd; 464 struct stat shm_stat; 465 EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); 466 // Neither the group, nor others should have been able to open the shared 467 // memory file while its name existed. 468 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); 469 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); 470} 471#endif // !defined(OS_ANDROID) 472 473#endif // defined(OS_POSIX) 474 475// Map() will return addresses which are aligned to the platform page size, this 476// varies from platform to platform though. Since we'd like to advertise a 477// minimum alignment that callers can count on, test for it here. 478TEST(SharedMemoryTest, MapMinimumAlignment) { 479 static const int kDataSize = 8192; 480 481 SharedMemory shared_memory; 482 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); 483 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>( 484 shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 485 shared_memory.Close(); 486} 487 488#if !defined(OS_IOS) // iOS does not allow multiple processes. 489 490// On POSIX it is especially important we test shmem across processes, 491// not just across threads. But the test is enabled on all platforms. 492class SharedMemoryProcessTest : public MultiProcessTest { 493 public: 494 495 static void CleanUp() { 496 SharedMemory memory; 497 memory.Delete(s_test_name_); 498 } 499 500 static int TaskTestMain() { 501 int errors = 0; 502#if defined(OS_MACOSX) 503 mac::ScopedNSAutoreleasePool pool; 504#endif 505 const uint32 kDataSize = 1024; 506 SharedMemory memory; 507 bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); 508 EXPECT_TRUE(rv); 509 if (rv != true) 510 errors++; 511 rv = memory.Map(kDataSize); 512 EXPECT_TRUE(rv); 513 if (rv != true) 514 errors++; 515 int *ptr = static_cast<int*>(memory.memory()); 516 517 for (int idx = 0; idx < 20; idx++) { 518 memory.Lock(); 519 int i = (1 << 16) + idx; 520 *ptr = i; 521 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); 522 if (*ptr != i) 523 errors++; 524 memory.Unlock(); 525 } 526 527 memory.Close(); 528 return errors; 529 } 530 531 private: 532 static const char* const s_test_name_; 533}; 534 535const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; 536 537TEST_F(SharedMemoryProcessTest, Tasks) { 538 SharedMemoryProcessTest::CleanUp(); 539 540 ProcessHandle handles[kNumTasks]; 541 for (int index = 0; index < kNumTasks; ++index) { 542 handles[index] = SpawnChild("SharedMemoryTestMain", false); 543 ASSERT_TRUE(handles[index]); 544 } 545 546 int exit_code = 0; 547 for (int index = 0; index < kNumTasks; ++index) { 548 EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code)); 549 EXPECT_EQ(0, exit_code); 550 } 551 552 SharedMemoryProcessTest::CleanUp(); 553} 554 555MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { 556 return SharedMemoryProcessTest::TaskTestMain(); 557} 558 559#endif // !OS_IOS 560 561} // namespace base 562