Index: base/memory/shared_memory_unittest.cc |
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc |
index 6fe57060e6fcd6cd83853875fcea4c1595c52138..c129e18d4c3049961ee1462cb93870c2485e594e 100644 |
--- a/base/memory/shared_memory_unittest.cc |
+++ b/base/memory/shared_memory_unittest.cc |
@@ -2,6 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include "base/atomicops.h" |
#include "base/basictypes.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/memory/shared_memory.h" |
@@ -33,7 +34,7 @@ |
#endif |
static const int kNumThreads = 5; |
-#if !defined(OS_IOS) // iOS does not allow multiple processes. |
+#if !defined(OS_IOS) && !defined(OS_ANDROID) |
static const int kNumTasks = 5; |
#endif |
@@ -90,56 +91,6 @@ class MultipleThreadMain : public PlatformThread::Delegate { |
const char* const MultipleThreadMain::s_test_name_ = |
"SharedMemoryOpenThreadTest"; |
-// TODO(port): |
-// This test requires the ability to pass file descriptors between processes. |
-// We haven't done that yet in Chrome for POSIX. |
-#if defined(OS_WIN) |
-// Each thread will open the shared memory. Each thread will take the memory, |
-// and keep changing it while trying to lock it, with some small pauses in |
-// between. Verify that each thread's value in the shared memory is always |
-// correct. |
-class MultipleLockThread : public PlatformThread::Delegate { |
- public: |
- explicit MultipleLockThread(int id) : id_(id) {} |
- ~MultipleLockThread() override {} |
- |
- // PlatformThread::Delegate interface. |
- void ThreadMain() override { |
- const uint32 kDataSize = sizeof(int); |
- SharedMemoryHandle handle = NULL; |
- { |
- SharedMemory memory1; |
- EXPECT_TRUE(memory1.CreateNamedDeprecated( |
- "SharedMemoryMultipleLockThreadTest", true, kDataSize)); |
- EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); |
- // TODO(paulg): Implement this once we have a posix version of |
- // SharedMemory::ShareToProcess. |
- EXPECT_TRUE(true); |
- } |
- |
- SharedMemory memory2(handle, false); |
- EXPECT_TRUE(memory2.Map(kDataSize)); |
- volatile int* const ptr = static_cast<int*>(memory2.memory()); |
- |
- for (int idx = 0; idx < 20; idx++) { |
- memory2.LockDeprecated(); |
- int i = (id_ << 16) + idx; |
- *ptr = i; |
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); |
- EXPECT_EQ(*ptr, i); |
- memory2.UnlockDeprecated(); |
- } |
- |
- memory2.Close(); |
- } |
- |
- private: |
- int id_; |
- |
- DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); |
-}; |
-#endif |
- |
} // namespace |
// Android doesn't support SharedMemory::Open/Delete/ |
@@ -320,34 +271,6 @@ TEST(SharedMemoryTest, MultipleThreads) { |
MultipleThreadMain::CleanUp(); |
} |
-// TODO(port): this test requires the MultipleLockThread class |
-// (defined above), which requires the ability to pass file |
-// descriptors between processes. We haven't done that yet in Chrome |
-// for POSIX. |
-#if defined(OS_WIN) |
-// Create a set of threads to each open a shared memory segment and write to it |
-// with the lock held. Verify that they are always reading/writing consistent |
-// data. |
-TEST(SharedMemoryTest, Lock) { |
- PlatformThreadHandle thread_handles[kNumThreads]; |
- MultipleLockThread* thread_delegates[kNumThreads]; |
- |
- // Spawn the threads. |
- for (int index = 0; index < kNumThreads; ++index) { |
- PlatformThreadHandle pth; |
- thread_delegates[index] = new MultipleLockThread(index); |
- EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); |
- thread_handles[index] = pth; |
- } |
- |
- // Wait for the threads to finish. |
- for (int index = 0; index < kNumThreads; ++index) { |
- PlatformThread::Join(thread_handles[index]); |
- delete thread_delegates[index]; |
- } |
-} |
-#endif |
- |
// Allocate private (unique) shared memory with an empty string for a |
// name. Make sure several of them don't point to the same thing as |
// we might expect if the names are equal. |
@@ -437,12 +360,13 @@ TEST(SharedMemoryTest, ShareReadOnly) { |
// http://crbug.com/320865 |
(void)handle; |
#elif defined(OS_POSIX) |
- EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE) |
+ int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle); |
+ EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE) |
<< "The descriptor itself should be read-only."; |
errno = 0; |
- void* writable = mmap( |
- NULL, contents.size(), PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0); |
+ void* writable = mmap(NULL, contents.size(), PROT_READ | PROT_WRITE, |
+ MAP_SHARED, handle_fd, 0); |
int mmap_errno = errno; |
EXPECT_EQ(MAP_FAILED, writable) |
<< "It shouldn't be possible to re-mmap the descriptor writable."; |
@@ -596,7 +520,8 @@ TEST(SharedMemoryTest, FilePermissionsAnonymous) { |
EXPECT_TRUE(shared_memory.Create(options)); |
- int shm_fd = shared_memory.handle().fd; |
+ int shm_fd = |
+ SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); |
struct stat shm_stat; |
EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); |
// Neither the group, nor others should be able to read the shared memory |
@@ -622,7 +547,8 @@ TEST(SharedMemoryTest, FilePermissionsNamed) { |
// Clean-up the backing file name immediately, we don't need it. |
EXPECT_TRUE(shared_memory.Delete(shared_mem_name)); |
- int shm_fd = shared_memory.handle().fd; |
+ int shm_fd = |
+ SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); |
struct stat shm_stat; |
EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); |
// Neither the group, nor others should have been able to open the shared |
@@ -647,7 +573,9 @@ TEST(SharedMemoryTest, MapMinimumAlignment) { |
shared_memory.Close(); |
} |
-#if !defined(OS_IOS) // iOS does not allow multiple processes. |
+// iOS does not allow multiple processes. |
+// Android ashmem doesn't support named shared memory. |
+#if !defined(OS_IOS) && !defined(OS_ANDROID) |
// On POSIX it is especially important we test shmem across processes, |
// not just across threads. But the test is enabled on all platforms. |
@@ -664,53 +592,61 @@ class SharedMemoryProcessTest : public MultiProcessTest { |
#if defined(OS_MACOSX) |
mac::ScopedNSAutoreleasePool pool; |
#endif |
- const uint32 kDataSize = 1024; |
SharedMemory memory; |
- bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize); |
+ bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); |
EXPECT_TRUE(rv); |
if (rv != true) |
errors++; |
- rv = memory.Map(kDataSize); |
+ rv = memory.Map(s_data_size_); |
EXPECT_TRUE(rv); |
if (rv != true) |
errors++; |
int *ptr = static_cast<int*>(memory.memory()); |
- for (int idx = 0; idx < 20; idx++) { |
- memory.LockDeprecated(); |
- int i = (1 << 16) + idx; |
- *ptr = i; |
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); |
- if (*ptr != i) |
- errors++; |
- memory.UnlockDeprecated(); |
- } |
- |
+ // This runs concurrently in multiple processes. Writes need to be atomic. |
+ base::subtle::Barrier_AtomicIncrement(ptr, 1); |
memory.Close(); |
return errors; |
} |
- private: |
static const char* const s_test_name_; |
+ static const uint32 s_data_size_; |
}; |
const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; |
+const uint32 SharedMemoryProcessTest::s_data_size_ = 1024; |
-TEST_F(SharedMemoryProcessTest, Tasks) { |
+TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) { |
SharedMemoryProcessTest::CleanUp(); |
+ // Create a shared memory region. Set the first word to 0. |
+ SharedMemory memory; |
+ bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); |
+ ASSERT_TRUE(rv); |
+ rv = memory.Map(s_data_size_); |
+ ASSERT_TRUE(rv); |
+ int* ptr = static_cast<int*>(memory.memory()); |
+ *ptr = 0; |
+ |
+ // Start |kNumTasks| processes, each of which atomically increments the first |
+ // word by 1. |
Process processes[kNumTasks]; |
for (int index = 0; index < kNumTasks; ++index) { |
processes[index] = SpawnChild("SharedMemoryTestMain"); |
ASSERT_TRUE(processes[index].IsValid()); |
} |
+ // Check that each process exited correctly. |
int exit_code = 0; |
for (int index = 0; index < kNumTasks; ++index) { |
EXPECT_TRUE(processes[index].WaitForExit(&exit_code)); |
EXPECT_EQ(0, exit_code); |
} |
+ // Check that the shared memory region reflects |kNumTasks| increments. |
+ ASSERT_EQ(kNumTasks, *ptr); |
+ |
+ memory.Close(); |
SharedMemoryProcessTest::CleanUp(); |
} |
@@ -718,6 +654,6 @@ MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { |
return SharedMemoryProcessTest::TaskTestMain(); |
} |
-#endif // !OS_IOS |
+#endif // !defined(OS_IOS) && !defined(OS_ANDROID) |
} // namespace base |