Chromium Code Reviews| 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..c36fca248fba6cd6adca2a9183154a24f4b68c13 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" |
| @@ -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. |
| @@ -664,53 +587,66 @@ 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, data_size_); |
| EXPECT_TRUE(rv); |
| if (rv != true) |
| errors++; |
| - rv = memory.Map(kDataSize); |
| + rv = memory.Map(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(); |
| + // Atomically increment the value at *ptr by 1. |
| + while (true) { |
| + int j = *ptr; |
| + int old_value = base::subtle::NoBarrier_CompareAndSwap(ptr, j, j + 1); |
|
Nico
2015/06/11 15:39:18
can you use a lock instead?
erikchen
2015/06/11 17:36:30
This code needs to be atomic across multiple proce
Nico
2015/06/11 17:46:40
Ah, right. Maybe say "// This runs concurrently in
erikchen
2015/06/11 17:55:18
Done.
That's weird. I thought I did use an atomic
|
| + if (old_value == j) |
| + break; |
| } |
| - |
| memory.Close(); |
| return errors; |
| } |
| - private: |
| static const char* const s_test_name_; |
| + static const uint32 data_size_; |
|
Nico
2015/06/11 15:39:18
s_data_size for consistency
erikchen
2015/06/11 17:36:30
Done.
|
| }; |
| const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; |
| +const uint32 SharedMemoryProcessTest::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, data_size_); |
| + ASSERT_TRUE(rv); |
| + rv = memory.Map(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(); |
| } |