| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 <process.h> // _beginthreadex | 5 #include "base/basictypes.h" |
| 6 #include "base/platform_thread.h" |
| 6 #include "base/shared_memory.h" | 7 #include "base/shared_memory.h" |
| 7 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
| 8 | 9 |
| 10 static const int kNumThreads = 5; |
| 9 | 11 |
| 10 namespace { | 12 namespace { |
| 11 | 13 |
| 12 class SharedMemoryTest : public testing::Test { | 14 class SharedMemoryTest : public testing::Test { |
| 13 }; | 15 }; |
| 14 | 16 |
| 15 unsigned __stdcall MultipleThreadMain(void* param) { | 17 // Each thread will open the shared memory. Each thread will take a different 4 |
| 16 // Each thread will open the shared memory. Each thread will take | 18 // byte int pointer, and keep changing it, with some small pauses in between. |
| 17 // a different 4 byte int pointer, and keep changing it, with some | 19 // Verify that each thread's value in the shared memory is always correct. |
| 18 // small pauses in between. Verify that each thread's value in the | 20 class MultipleThreadMain : public PlatformThread::Delegate { |
| 19 // shared memory is always correct. | 21 public: |
| 20 const int kDataSize = 1024; | 22 explicit MultipleThreadMain(int16 id) : id_(id) {} |
| 21 std::wstring test_name = L"SharedMemoryOpenThreadTest"; | 23 ~MultipleThreadMain() {} |
| 22 int16 id = reinterpret_cast<int16>(param); | 24 |
| 23 SharedMemory memory; | 25 // PlatformThread::Delegate interface. |
| 24 bool rv = memory.Create(test_name, false, true, kDataSize); | 26 void ThreadMain() { |
| 25 EXPECT_TRUE(rv); | 27 const int kDataSize = 1024; |
| 26 rv = memory.Map(kDataSize); | 28 std::wstring test_name = L"SharedMemoryOpenThreadTest"; |
| 27 EXPECT_TRUE(rv); | 29 SharedMemory memory; |
| 28 int *ptr = static_cast<int*>(memory.memory()) + id; | 30 bool rv = memory.Create(test_name, false, true, kDataSize); |
| 29 EXPECT_EQ(*ptr, 0); | 31 EXPECT_TRUE(rv); |
| 30 for (int idx = 0; idx < 100; idx++) { | 32 rv = memory.Map(kDataSize); |
| 31 *ptr = idx; | 33 EXPECT_TRUE(rv); |
| 32 Sleep(1); // short wait | 34 int *ptr = static_cast<int*>(memory.memory()) + id_; |
| 33 EXPECT_EQ(*ptr, idx); | 35 EXPECT_EQ(*ptr, 0); |
| 36 |
| 37 for (int idx = 0; idx < 100; idx++) { |
| 38 *ptr = idx; |
| 39 PlatformThread::Sleep(1); // Short wait. |
| 40 EXPECT_EQ(*ptr, idx); |
| 41 } |
| 42 |
| 43 memory.Close(); |
| 34 } | 44 } |
| 35 memory.Close(); | |
| 36 return 0; | |
| 37 } | |
| 38 | 45 |
| 39 unsigned __stdcall MultipleLockThread(void* param) { | 46 private: |
| 40 // Each thread will open the shared memory. Each thread will take | 47 int16 id_; |
| 41 // the memory, and keep changing it while trying to lock it, with some | 48 |
| 42 // small pauses in between. Verify that each thread's value in the | 49 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); |
| 43 // shared memory is always correct. | 50 }; |
| 44 const int kDataSize = sizeof(int); | 51 |
| 45 int id = static_cast<int>(reinterpret_cast<INT_PTR>(param)); | 52 #if defined(OS_WIN) |
| 46 SharedMemoryHandle handle = NULL; | 53 // Each thread will open the shared memory. Each thread will take the memory, |
| 47 { | 54 // and keep changing it while trying to lock it, with some small pauses in |
| 48 SharedMemory memory1; | 55 // between. Verify that each thread's value in the shared memory is always |
| 49 EXPECT_TRUE(memory1.Create(L"SharedMemoryMultipleLockThreadTest", false, tru
e, | 56 // correct. |
| 50 kDataSize)); | 57 class MultipleLockThread : public PlatformThread::Delegate { |
| 51 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); | 58 public: |
| 59 explicit MultipleLockThread(int id) : id_(id) {} |
| 60 ~MultipleLockThread() {} |
| 61 |
| 62 // PlatformThread::Delegate interface. |
| 63 void ThreadMain() { |
| 64 const int kDataSize = sizeof(int); |
| 65 SharedMemoryHandle handle = NULL; |
| 66 { |
| 67 SharedMemory memory1; |
| 68 EXPECT_TRUE(memory1.Create(L"SharedMemoryMultipleLockThreadTest", |
| 69 false, true, kDataSize)); |
| 70 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); |
| 71 // TODO(paulg): Implement this once we have a posix version of |
| 72 // SharedMemory::ShareToProcess. |
| 73 EXPECT_TRUE(true); |
| 74 } |
| 75 |
| 76 SharedMemory memory2(handle, false); |
| 77 EXPECT_TRUE(memory2.Map(kDataSize)); |
| 78 volatile int* const ptr = static_cast<int*>(memory2.memory()); |
| 79 |
| 80 for (int idx = 0; idx < 20; idx++) { |
| 81 memory2.Lock(); |
| 82 int i = (id_ << 16) + idx; |
| 83 *ptr = i; |
| 84 PlatformThread::Sleep(1); // Short wait. |
| 85 EXPECT_EQ(*ptr, i); |
| 86 memory2.Unlock(); |
| 87 } |
| 88 |
| 89 memory2.Close(); |
| 52 } | 90 } |
| 53 SharedMemory memory2(handle, false); | 91 |
| 54 EXPECT_TRUE(memory2.Map(kDataSize)); | 92 private: |
| 55 volatile int* const ptr = static_cast<int*>(memory2.memory()); | 93 int id_; |
| 56 for (int idx = 0; idx < 20; idx++) { | 94 |
| 57 memory2.Lock(); | 95 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); |
| 58 int i = (id << 16) + idx; | 96 }; |
| 59 *ptr = i; | 97 #endif |
| 60 // short wait | |
| 61 Sleep(1); | |
| 62 EXPECT_EQ(*ptr, i); | |
| 63 memory2.Unlock(); | |
| 64 } | |
| 65 memory2.Close(); | |
| 66 return 0; | |
| 67 } | |
| 68 | 98 |
| 69 } // namespace | 99 } // namespace |
| 70 | 100 |
| 71 TEST(SharedMemoryTest, OpenClose) { | 101 TEST(SharedMemoryTest, OpenClose) { |
| 72 const int kDataSize = 1024; | 102 const int kDataSize = 1024; |
| 73 std::wstring test_name = L"SharedMemoryOpenCloseTest"; | 103 std::wstring test_name = L"SharedMemoryOpenCloseTest"; |
| 74 | 104 |
| 75 // Open two handles to a memory segment, confirm that they | 105 // Open two handles to a memory segment, confirm that they are mapped |
| 76 // are mapped separately yet point to the same space. | 106 // separately yet point to the same space. |
| 77 SharedMemory memory1; | 107 SharedMemory memory1; |
| 78 bool rv = memory1.Open(test_name, false); | 108 bool rv = memory1.Open(test_name, false); |
| 79 EXPECT_FALSE(rv); | 109 EXPECT_FALSE(rv); |
| 80 rv = memory1.Create(test_name, false, false, kDataSize); | 110 rv = memory1.Create(test_name, false, false, kDataSize); |
| 81 EXPECT_TRUE(rv); | 111 EXPECT_TRUE(rv); |
| 82 rv = memory1.Map(kDataSize); | 112 rv = memory1.Map(kDataSize); |
| 83 EXPECT_TRUE(rv); | 113 EXPECT_TRUE(rv); |
| 84 SharedMemory memory2; | 114 SharedMemory memory2; |
| 85 rv = memory2.Open(test_name, false); | 115 rv = memory2.Open(test_name, false); |
| 86 EXPECT_TRUE(rv); | 116 EXPECT_TRUE(rv); |
| 87 rv = memory2.Map(kDataSize); | 117 rv = memory2.Map(kDataSize); |
| 88 EXPECT_TRUE(rv); | 118 EXPECT_TRUE(rv); |
| 89 EXPECT_NE(memory1.memory(), memory2.memory()); // compare the pointers | 119 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. |
| 90 | 120 |
| 91 | 121 |
| 92 // Write data to the first memory segment, verify contents of second. | 122 // Write data to the first memory segment, verify contents of second. |
| 93 memset(memory1.memory(), '1', kDataSize); | 123 memset(memory1.memory(), '1', kDataSize); |
| 94 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); | 124 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); |
| 95 | 125 |
| 96 // Close the first memory segment, and verify the | 126 // Close the first memory segment, and verify the second has the right data. |
| 97 // second still has the right data. | |
| 98 memory1.Close(); | 127 memory1.Close(); |
| 99 char *start_ptr = static_cast<char *>(memory2.memory()); | 128 char *start_ptr = static_cast<char *>(memory2.memory()); |
| 100 char *end_ptr = start_ptr + kDataSize; | 129 char *end_ptr = start_ptr + kDataSize; |
| 101 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) | 130 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) |
| 102 EXPECT_EQ(*ptr, '1'); | 131 EXPECT_EQ(*ptr, '1'); |
| 103 | 132 |
| 104 // Close the second memory segment | 133 // Close the second memory segment. |
| 105 memory2.Close(); | 134 memory2.Close(); |
| 106 } | 135 } |
| 107 | 136 |
| 108 | 137 #if defined(OS_WIN) |
| 138 // Create a set of 5 threads to each open a shared memory segment and write to |
| 139 // it. Verify that they are always reading/writing consistent data. |
| 109 TEST(SharedMemoryTest, MultipleThreads) { | 140 TEST(SharedMemoryTest, MultipleThreads) { |
| 110 // Create a set of 5 threads to each open a shared memory segment | 141 PlatformThreadHandle thread_handles[kNumThreads]; |
| 111 // and write to it. Verify that they are always reading/writing | 142 MultipleThreadMain* thread_delegates[kNumThreads]; |
| 112 // consistent data. | |
| 113 const int kNumThreads = 5; | |
| 114 HANDLE threads[kNumThreads]; | |
| 115 | 143 |
| 116 // Spawn the threads. | 144 // Spawn the threads. |
| 117 for (int16 index = 0; index < kNumThreads; index++) { | 145 for (int16 index = 0; index < kNumThreads; index++) { |
| 118 void *argument = reinterpret_cast<void*>(index); | 146 PlatformThreadHandle pth; |
| 119 unsigned thread_id; | 147 thread_delegates[index] = new MultipleThreadMain(index); |
| 120 threads[index] = reinterpret_cast<HANDLE>( | 148 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); |
| 121 _beginthreadex(NULL, 0, MultipleThreadMain, argument, 0, &thread_id)); | 149 thread_handles[index] = pth; |
| 122 EXPECT_NE(threads[index], static_cast<HANDLE>(NULL)); | |
| 123 } | 150 } |
| 124 | 151 |
| 125 // Wait for the threads to finish. | 152 // Wait for the threads to finish. |
| 126 for (int index = 0; index < kNumThreads; index++) { | 153 for (int index = 0; index < kNumThreads; index++) { |
| 127 DWORD rv = WaitForSingleObject(threads[index], 60*1000); | 154 PlatformThread::Join(thread_handles[index]); |
| 128 EXPECT_EQ(rv, WAIT_OBJECT_0); // verify all threads finished | 155 delete thread_delegates[index]; |
| 129 CloseHandle(threads[index]); | |
| 130 } | 156 } |
| 131 } | 157 } |
| 132 | 158 |
| 133 | 159 // Create a set of threads to each open a shared memory segment and write to it |
| 160 // with the lock held. Verify that they are always reading/writing consistent |
| 161 // data. |
| 134 TEST(SharedMemoryTest, Lock) { | 162 TEST(SharedMemoryTest, Lock) { |
| 135 // Create a set of threads to each open a shared memory segment and write to | 163 PlatformThreadHandle thread_handles[kNumThreads]; |
| 136 // it with the lock held. Verify that they are always reading/writing | 164 MultipleLockThread* thread_delegates[kNumThreads]; |
| 137 // consistent data. | |
| 138 const int kNumThreads = 5; | |
| 139 HANDLE threads[kNumThreads]; | |
| 140 | 165 |
| 141 // Spawn the threads. | 166 // Spawn the threads. |
| 142 for (int index = 0; index < kNumThreads; ++index) { | 167 for (int index = 0; index < kNumThreads; ++index) { |
| 143 void *argument = reinterpret_cast<void*>(static_cast<INT_PTR>(index)); | 168 PlatformThreadHandle pth; |
| 144 threads[index] = reinterpret_cast<HANDLE>( | 169 thread_delegates[index] = new MultipleLockThread(index); |
| 145 _beginthreadex(NULL, 0, &MultipleLockThread, argument, 0, NULL)); | 170 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); |
| 146 EXPECT_NE(threads[index], static_cast<HANDLE>(NULL)); | 171 thread_handles[index] = pth; |
| 147 } | 172 } |
| 148 | 173 |
| 149 // Wait for the threads to finish. | 174 // Wait for the threads to finish. |
| 150 for (int index = 0; index < kNumThreads; ++index) { | 175 for (int index = 0; index < kNumThreads; ++index) { |
| 151 DWORD rv = WaitForSingleObject(threads[index], 60*1000); | 176 PlatformThread::Join(thread_handles[index]); |
| 152 EXPECT_EQ(rv, WAIT_OBJECT_0); // verify all threads finished | 177 delete thread_delegates[index]; |
| 153 CloseHandle(threads[index]); | |
| 154 } | 178 } |
| 155 } | 179 } |
| 156 | 180 #endif |
| OLD | NEW |