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 "base/atomicops.h" |
5 #include "base/basictypes.h" | 6 #include "base/basictypes.h" |
6 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
7 #include "base/memory/shared_memory.h" | 8 #include "base/memory/shared_memory.h" |
8 #include "base/process/kill.h" | 9 #include "base/process/kill.h" |
9 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
11 #include "base/sys_info.h" | 12 #include "base/sys_info.h" |
12 #include "base/test/multiprocess_test.h" | 13 #include "base/test/multiprocess_test.h" |
13 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
14 #include "base/time/time.h" | 15 #include "base/time/time.h" |
(...skipping 11 matching lines...) Expand all Loading... |
26 #include <sys/stat.h> | 27 #include <sys/stat.h> |
27 #include <sys/types.h> | 28 #include <sys/types.h> |
28 #include <unistd.h> | 29 #include <unistd.h> |
29 #endif | 30 #endif |
30 | 31 |
31 #if defined(OS_WIN) | 32 #if defined(OS_WIN) |
32 #include "base/win/scoped_handle.h" | 33 #include "base/win/scoped_handle.h" |
33 #endif | 34 #endif |
34 | 35 |
35 static const int kNumThreads = 5; | 36 static const int kNumThreads = 5; |
36 #if !defined(OS_IOS) // iOS does not allow multiple processes. | 37 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
37 static const int kNumTasks = 5; | 38 static const int kNumTasks = 5; |
38 #endif | 39 #endif |
39 | 40 |
40 namespace base { | 41 namespace base { |
41 | 42 |
42 namespace { | 43 namespace { |
43 | 44 |
44 // Each thread will open the shared memory. Each thread will take a different 4 | 45 // Each thread will open the shared memory. Each thread will take a different 4 |
45 // byte int pointer, and keep changing it, with some small pauses in between. | 46 // byte int pointer, and keep changing it, with some small pauses in between. |
46 // Verify that each thread's value in the shared memory is always correct. | 47 // Verify that each thread's value in the shared memory is always correct. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 int16 id_; | 84 int16 id_; |
84 | 85 |
85 static const char* const s_test_name_; | 86 static const char* const s_test_name_; |
86 | 87 |
87 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); | 88 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); |
88 }; | 89 }; |
89 | 90 |
90 const char* const MultipleThreadMain::s_test_name_ = | 91 const char* const MultipleThreadMain::s_test_name_ = |
91 "SharedMemoryOpenThreadTest"; | 92 "SharedMemoryOpenThreadTest"; |
92 | 93 |
93 // TODO(port): | |
94 // This test requires the ability to pass file descriptors between processes. | |
95 // We haven't done that yet in Chrome for POSIX. | |
96 #if defined(OS_WIN) | |
97 // Each thread will open the shared memory. Each thread will take the memory, | |
98 // and keep changing it while trying to lock it, with some small pauses in | |
99 // between. Verify that each thread's value in the shared memory is always | |
100 // correct. | |
101 class MultipleLockThread : public PlatformThread::Delegate { | |
102 public: | |
103 explicit MultipleLockThread(int id) : id_(id) {} | |
104 ~MultipleLockThread() override {} | |
105 | |
106 // PlatformThread::Delegate interface. | |
107 void ThreadMain() override { | |
108 const uint32 kDataSize = sizeof(int); | |
109 SharedMemoryHandle handle = NULL; | |
110 { | |
111 SharedMemory memory1; | |
112 EXPECT_TRUE(memory1.CreateNamedDeprecated( | |
113 "SharedMemoryMultipleLockThreadTest", true, kDataSize)); | |
114 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); | |
115 // TODO(paulg): Implement this once we have a posix version of | |
116 // SharedMemory::ShareToProcess. | |
117 EXPECT_TRUE(true); | |
118 } | |
119 | |
120 SharedMemory memory2(handle, false); | |
121 EXPECT_TRUE(memory2.Map(kDataSize)); | |
122 volatile int* const ptr = static_cast<int*>(memory2.memory()); | |
123 | |
124 for (int idx = 0; idx < 20; idx++) { | |
125 memory2.LockDeprecated(); | |
126 int i = (id_ << 16) + idx; | |
127 *ptr = i; | |
128 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); | |
129 EXPECT_EQ(*ptr, i); | |
130 memory2.UnlockDeprecated(); | |
131 } | |
132 | |
133 memory2.Close(); | |
134 } | |
135 | |
136 private: | |
137 int id_; | |
138 | |
139 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); | |
140 }; | |
141 #endif | |
142 | |
143 } // namespace | 94 } // namespace |
144 | 95 |
145 // Android doesn't support SharedMemory::Open/Delete/ | 96 // Android doesn't support SharedMemory::Open/Delete/ |
146 // CreateNamedDeprecated(openExisting=true) | 97 // CreateNamedDeprecated(openExisting=true) |
147 #if !defined(OS_ANDROID) | 98 #if !defined(OS_ANDROID) |
148 TEST(SharedMemoryTest, OpenClose) { | 99 TEST(SharedMemoryTest, OpenClose) { |
149 const uint32 kDataSize = 1024; | 100 const uint32 kDataSize = 1024; |
150 std::string test_name = "SharedMemoryOpenCloseTest"; | 101 std::string test_name = "SharedMemoryOpenCloseTest"; |
151 | 102 |
152 // Open two handles to a memory segment, confirm that they are mapped | 103 // Open two handles to a memory segment, confirm that they are mapped |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 | 264 |
314 // Wait for the threads to finish. | 265 // Wait for the threads to finish. |
315 for (int index = 0; index < numthreads; index++) { | 266 for (int index = 0; index < numthreads; index++) { |
316 PlatformThread::Join(thread_handles[index]); | 267 PlatformThread::Join(thread_handles[index]); |
317 delete thread_delegates[index]; | 268 delete thread_delegates[index]; |
318 } | 269 } |
319 } | 270 } |
320 MultipleThreadMain::CleanUp(); | 271 MultipleThreadMain::CleanUp(); |
321 } | 272 } |
322 | 273 |
323 // TODO(port): this test requires the MultipleLockThread class | |
324 // (defined above), which requires the ability to pass file | |
325 // descriptors between processes. We haven't done that yet in Chrome | |
326 // for POSIX. | |
327 #if defined(OS_WIN) | |
328 // Create a set of threads to each open a shared memory segment and write to it | |
329 // with the lock held. Verify that they are always reading/writing consistent | |
330 // data. | |
331 TEST(SharedMemoryTest, Lock) { | |
332 PlatformThreadHandle thread_handles[kNumThreads]; | |
333 MultipleLockThread* thread_delegates[kNumThreads]; | |
334 | |
335 // Spawn the threads. | |
336 for (int index = 0; index < kNumThreads; ++index) { | |
337 PlatformThreadHandle pth; | |
338 thread_delegates[index] = new MultipleLockThread(index); | |
339 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); | |
340 thread_handles[index] = pth; | |
341 } | |
342 | |
343 // Wait for the threads to finish. | |
344 for (int index = 0; index < kNumThreads; ++index) { | |
345 PlatformThread::Join(thread_handles[index]); | |
346 delete thread_delegates[index]; | |
347 } | |
348 } | |
349 #endif | |
350 | |
351 // Allocate private (unique) shared memory with an empty string for a | 274 // Allocate private (unique) shared memory with an empty string for a |
352 // name. Make sure several of them don't point to the same thing as | 275 // name. Make sure several of them don't point to the same thing as |
353 // we might expect if the names are equal. | 276 // we might expect if the names are equal. |
354 TEST(SharedMemoryTest, AnonymousPrivate) { | 277 TEST(SharedMemoryTest, AnonymousPrivate) { |
355 int i, j; | 278 int i, j; |
356 int count = 4; | 279 int count = 4; |
357 bool rv; | 280 bool rv; |
358 const uint32 kDataSize = 8192; | 281 const uint32 kDataSize = 8192; |
359 | 282 |
360 scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]); | 283 scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]); |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 TEST(SharedMemoryTest, MapMinimumAlignment) { | 563 TEST(SharedMemoryTest, MapMinimumAlignment) { |
641 static const int kDataSize = 8192; | 564 static const int kDataSize = 8192; |
642 | 565 |
643 SharedMemory shared_memory; | 566 SharedMemory shared_memory; |
644 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); | 567 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); |
645 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>( | 568 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>( |
646 shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); | 569 shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); |
647 shared_memory.Close(); | 570 shared_memory.Close(); |
648 } | 571 } |
649 | 572 |
650 #if !defined(OS_IOS) // iOS does not allow multiple processes. | 573 // iOS does not allow multiple processes. |
| 574 // Android ashmem doesn't support named shared memory. |
| 575 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
651 | 576 |
652 // On POSIX it is especially important we test shmem across processes, | 577 // On POSIX it is especially important we test shmem across processes, |
653 // not just across threads. But the test is enabled on all platforms. | 578 // not just across threads. But the test is enabled on all platforms. |
654 class SharedMemoryProcessTest : public MultiProcessTest { | 579 class SharedMemoryProcessTest : public MultiProcessTest { |
655 public: | 580 public: |
656 | 581 |
657 static void CleanUp() { | 582 static void CleanUp() { |
658 SharedMemory memory; | 583 SharedMemory memory; |
659 memory.Delete(s_test_name_); | 584 memory.Delete(s_test_name_); |
660 } | 585 } |
661 | 586 |
662 static int TaskTestMain() { | 587 static int TaskTestMain() { |
663 int errors = 0; | 588 int errors = 0; |
664 #if defined(OS_MACOSX) | 589 #if defined(OS_MACOSX) |
665 mac::ScopedNSAutoreleasePool pool; | 590 mac::ScopedNSAutoreleasePool pool; |
666 #endif | 591 #endif |
667 const uint32 kDataSize = 1024; | |
668 SharedMemory memory; | 592 SharedMemory memory; |
669 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize); | 593 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); |
670 EXPECT_TRUE(rv); | 594 EXPECT_TRUE(rv); |
671 if (rv != true) | 595 if (rv != true) |
672 errors++; | 596 errors++; |
673 rv = memory.Map(kDataSize); | 597 rv = memory.Map(s_data_size_); |
674 EXPECT_TRUE(rv); | 598 EXPECT_TRUE(rv); |
675 if (rv != true) | 599 if (rv != true) |
676 errors++; | 600 errors++; |
677 int *ptr = static_cast<int*>(memory.memory()); | 601 int *ptr = static_cast<int*>(memory.memory()); |
678 | 602 |
679 for (int idx = 0; idx < 20; idx++) { | 603 // This runs concurrently in multiple processes. Writes need to be atomic. |
680 memory.LockDeprecated(); | 604 base::subtle::Barrier_AtomicIncrement(ptr, 1); |
681 int i = (1 << 16) + idx; | |
682 *ptr = i; | |
683 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); | |
684 if (*ptr != i) | |
685 errors++; | |
686 memory.UnlockDeprecated(); | |
687 } | |
688 | |
689 memory.Close(); | 605 memory.Close(); |
690 return errors; | 606 return errors; |
691 } | 607 } |
692 | 608 |
693 private: | |
694 static const char* const s_test_name_; | 609 static const char* const s_test_name_; |
| 610 static const uint32 s_data_size_; |
695 }; | 611 }; |
696 | 612 |
697 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; | 613 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; |
| 614 const uint32 SharedMemoryProcessTest::s_data_size_ = 1024; |
698 | 615 |
699 TEST_F(SharedMemoryProcessTest, Tasks) { | 616 TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) { |
700 SharedMemoryProcessTest::CleanUp(); | 617 SharedMemoryProcessTest::CleanUp(); |
701 | 618 |
| 619 // Create a shared memory region. Set the first word to 0. |
| 620 SharedMemory memory; |
| 621 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); |
| 622 ASSERT_TRUE(rv); |
| 623 rv = memory.Map(s_data_size_); |
| 624 ASSERT_TRUE(rv); |
| 625 int* ptr = static_cast<int*>(memory.memory()); |
| 626 *ptr = 0; |
| 627 |
| 628 // Start |kNumTasks| processes, each of which atomically increments the first |
| 629 // word by 1. |
702 Process processes[kNumTasks]; | 630 Process processes[kNumTasks]; |
703 for (int index = 0; index < kNumTasks; ++index) { | 631 for (int index = 0; index < kNumTasks; ++index) { |
704 processes[index] = SpawnChild("SharedMemoryTestMain"); | 632 processes[index] = SpawnChild("SharedMemoryTestMain"); |
705 ASSERT_TRUE(processes[index].IsValid()); | 633 ASSERT_TRUE(processes[index].IsValid()); |
706 } | 634 } |
707 | 635 |
| 636 // Check that each process exited correctly. |
708 int exit_code = 0; | 637 int exit_code = 0; |
709 for (int index = 0; index < kNumTasks; ++index) { | 638 for (int index = 0; index < kNumTasks; ++index) { |
710 EXPECT_TRUE(processes[index].WaitForExit(&exit_code)); | 639 EXPECT_TRUE(processes[index].WaitForExit(&exit_code)); |
711 EXPECT_EQ(0, exit_code); | 640 EXPECT_EQ(0, exit_code); |
712 } | 641 } |
713 | 642 |
| 643 // Check that the shared memory region reflects |kNumTasks| increments. |
| 644 ASSERT_EQ(kNumTasks, *ptr); |
| 645 |
| 646 memory.Close(); |
714 SharedMemoryProcessTest::CleanUp(); | 647 SharedMemoryProcessTest::CleanUp(); |
715 } | 648 } |
716 | 649 |
717 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { | 650 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { |
718 return SharedMemoryProcessTest::TaskTestMain(); | 651 return SharedMemoryProcessTest::TaskTestMain(); |
719 } | 652 } |
720 | 653 |
721 #endif // !OS_IOS | 654 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) |
722 | 655 |
723 } // namespace base | 656 } // namespace base |
OLD | NEW |