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 |