blob: 459b423262bbdd477cdf650d673e3401a5a3c6f1 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
paulg@google.com78da6632008-09-11 09:31:43 +09005#include "base/basictypes.h"
jrg@chromium.org81e22602009-02-06 04:04:34 +09006#include "base/multiprocess_test.h"
paulg@google.com78da6632008-09-11 09:31:43 +09007#include "base/platform_thread.h"
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +09008#include "base/scoped_nsautorelease_pool.h"
initial.commit3f4a7322008-07-27 06:49:38 +09009#include "base/shared_memory.h"
jrg@chromium.org81e22602009-02-06 04:04:34 +090010#include "base/scoped_ptr.h"
initial.commit3f4a7322008-07-27 06:49:38 +090011#include "testing/gtest/include/gtest/gtest.h"
12
paulg@google.com78da6632008-09-11 09:31:43 +090013static const int kNumThreads = 5;
jrg@chromium.org81e22602009-02-06 04:04:34 +090014static const int kNumTasks = 5;
initial.commit3f4a7322008-07-27 06:49:38 +090015
brettw@google.comc60d9892008-11-14 12:25:15 +090016namespace base {
initial.commit3f4a7322008-07-27 06:49:38 +090017
brettw@google.comc60d9892008-11-14 12:25:15 +090018namespace {
initial.commit3f4a7322008-07-27 06:49:38 +090019
paulg@google.com78da6632008-09-11 09:31:43 +090020// Each thread will open the shared memory. Each thread will take a different 4
21// byte int pointer, and keep changing it, with some small pauses in between.
22// Verify that each thread's value in the shared memory is always correct.
23class MultipleThreadMain : public PlatformThread::Delegate {
24 public:
25 explicit MultipleThreadMain(int16 id) : id_(id) {}
26 ~MultipleThreadMain() {}
initial.commit3f4a7322008-07-27 06:49:38 +090027
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +090028 static void CleanUp() {
29 SharedMemory memory;
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090030 memory.Delete(s_test_name_);
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +090031 }
32
paulg@google.com78da6632008-09-11 09:31:43 +090033 // PlatformThread::Delegate interface.
34 void ThreadMain() {
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +090035 ScopedNSAutoreleasePool pool; // noop if not OSX
jam@chromium.orge74ca942010-02-17 08:58:27 +090036 const uint32 kDataSize = 1024;
paulg@google.com78da6632008-09-11 09:31:43 +090037 SharedMemory memory;
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090038 bool rv = memory.Create(s_test_name_, false, true, kDataSize);
paulg@google.com78da6632008-09-11 09:31:43 +090039 EXPECT_TRUE(rv);
40 rv = memory.Map(kDataSize);
41 EXPECT_TRUE(rv);
42 int *ptr = static_cast<int*>(memory.memory()) + id_;
43 EXPECT_EQ(*ptr, 0);
44
45 for (int idx = 0; idx < 100; idx++) {
46 *ptr = idx;
47 PlatformThread::Sleep(1); // Short wait.
48 EXPECT_EQ(*ptr, idx);
49 }
50
51 memory.Close();
initial.commit3f4a7322008-07-27 06:49:38 +090052 }
paulg@google.com78da6632008-09-11 09:31:43 +090053
54 private:
55 int16 id_;
56
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090057 static const wchar_t* const s_test_name_;
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +090058
paulg@google.com78da6632008-09-11 09:31:43 +090059 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
60};
61
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090062const wchar_t* const MultipleThreadMain::s_test_name_ =
63 L"SharedMemoryOpenThreadTest";
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +090064
65// TODO(port):
66// This test requires the ability to pass file descriptors between processes.
67// We haven't done that yet in Chrome for POSIX.
paulg@google.com78da6632008-09-11 09:31:43 +090068#if defined(OS_WIN)
69// Each thread will open the shared memory. Each thread will take the memory,
70// and keep changing it while trying to lock it, with some small pauses in
71// between. Verify that each thread's value in the shared memory is always
72// correct.
73class MultipleLockThread : public PlatformThread::Delegate {
74 public:
75 explicit MultipleLockThread(int id) : id_(id) {}
76 ~MultipleLockThread() {}
77
78 // PlatformThread::Delegate interface.
79 void ThreadMain() {
jam@chromium.orge74ca942010-02-17 08:58:27 +090080 const uint32 kDataSize = sizeof(int);
paulg@google.com78da6632008-09-11 09:31:43 +090081 SharedMemoryHandle handle = NULL;
82 {
83 SharedMemory memory1;
84 EXPECT_TRUE(memory1.Create(L"SharedMemoryMultipleLockThreadTest",
85 false, true, kDataSize));
86 EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
87 // TODO(paulg): Implement this once we have a posix version of
88 // SharedMemory::ShareToProcess.
89 EXPECT_TRUE(true);
90 }
91
92 SharedMemory memory2(handle, false);
93 EXPECT_TRUE(memory2.Map(kDataSize));
94 volatile int* const ptr = static_cast<int*>(memory2.memory());
95
96 for (int idx = 0; idx < 20; idx++) {
97 memory2.Lock();
98 int i = (id_ << 16) + idx;
99 *ptr = i;
100 PlatformThread::Sleep(1); // Short wait.
101 EXPECT_EQ(*ptr, i);
102 memory2.Unlock();
103 }
104
105 memory2.Close();
initial.commit3f4a7322008-07-27 06:49:38 +0900106 }
paulg@google.com78da6632008-09-11 09:31:43 +0900107
108 private:
109 int id_;
110
111 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
112};
113#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900114
115} // namespace
116
117TEST(SharedMemoryTest, OpenClose) {
jam@chromium.orge74ca942010-02-17 08:58:27 +0900118 const uint32 kDataSize = 1024;
initial.commit3f4a7322008-07-27 06:49:38 +0900119 std::wstring test_name = L"SharedMemoryOpenCloseTest";
120
paulg@google.com78da6632008-09-11 09:31:43 +0900121 // Open two handles to a memory segment, confirm that they are mapped
122 // separately yet point to the same space.
initial.commit3f4a7322008-07-27 06:49:38 +0900123 SharedMemory memory1;
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900124 bool rv = memory1.Delete(test_name);
125 EXPECT_TRUE(rv);
126 rv = memory1.Delete(test_name);
127 EXPECT_TRUE(rv);
128 rv = memory1.Open(test_name, false);
initial.commit3f4a7322008-07-27 06:49:38 +0900129 EXPECT_FALSE(rv);
130 rv = memory1.Create(test_name, false, false, kDataSize);
131 EXPECT_TRUE(rv);
132 rv = memory1.Map(kDataSize);
133 EXPECT_TRUE(rv);
134 SharedMemory memory2;
135 rv = memory2.Open(test_name, false);
136 EXPECT_TRUE(rv);
137 rv = memory2.Map(kDataSize);
138 EXPECT_TRUE(rv);
paulg@google.com78da6632008-09-11 09:31:43 +0900139 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers.
initial.commit3f4a7322008-07-27 06:49:38 +0900140
maruel@google.com76cff082008-09-13 02:41:52 +0900141 // Make sure we don't segfault. (it actually happened!)
142 ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
143 ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
initial.commit3f4a7322008-07-27 06:49:38 +0900144
145 // Write data to the first memory segment, verify contents of second.
146 memset(memory1.memory(), '1', kDataSize);
147 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
148
paulg@google.com78da6632008-09-11 09:31:43 +0900149 // Close the first memory segment, and verify the second has the right data.
initial.commit3f4a7322008-07-27 06:49:38 +0900150 memory1.Close();
151 char *start_ptr = static_cast<char *>(memory2.memory());
152 char *end_ptr = start_ptr + kDataSize;
153 for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
154 EXPECT_EQ(*ptr, '1');
155
paulg@google.com78da6632008-09-11 09:31:43 +0900156 // Close the second memory segment.
initial.commit3f4a7322008-07-27 06:49:38 +0900157 memory2.Close();
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900158
159 rv = memory1.Delete(test_name);
160 EXPECT_TRUE(rv);
161 rv = memory2.Delete(test_name);
162 EXPECT_TRUE(rv);
initial.commit3f4a7322008-07-27 06:49:38 +0900163}
164
jrg@chromium.org81e22602009-02-06 04:04:34 +0900165// Create a set of N threads to each open a shared memory segment and write to
paulg@google.com78da6632008-09-11 09:31:43 +0900166// it. Verify that they are always reading/writing consistent data.
initial.commit3f4a7322008-07-27 06:49:38 +0900167TEST(SharedMemoryTest, MultipleThreads) {
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900168 MultipleThreadMain::CleanUp();
jrg@chromium.org81e22602009-02-06 04:04:34 +0900169 // On POSIX we have a problem when 2 threads try to create the shmem
170 // (a file) at exactly the same time, since create both creates the
171 // file and zerofills it. We solve the problem for this unit test
172 // (make it not flaky) by starting with 1 thread, then
173 // intentionally don't clean up its shmem before running with
174 // kNumThreads.
initial.commit3f4a7322008-07-27 06:49:38 +0900175
jrg@chromium.org81e22602009-02-06 04:04:34 +0900176 int threadcounts[] = { 1, kNumThreads };
177 for (size_t i = 0; i < sizeof(threadcounts) / sizeof(threadcounts); i++) {
178 int numthreads = threadcounts[i];
179 scoped_array<PlatformThreadHandle> thread_handles;
180 scoped_array<MultipleThreadMain*> thread_delegates;
181
182 thread_handles.reset(new PlatformThreadHandle[numthreads]);
183 thread_delegates.reset(new MultipleThreadMain*[numthreads]);
184
185 // Spawn the threads.
186 for (int16 index = 0; index < numthreads; index++) {
187 PlatformThreadHandle pth;
188 thread_delegates[index] = new MultipleThreadMain(index);
189 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
190 thread_handles[index] = pth;
191 }
192
193 // Wait for the threads to finish.
194 for (int index = 0; index < numthreads; index++) {
195 PlatformThread::Join(thread_handles[index]);
196 delete thread_delegates[index];
197 }
initial.commit3f4a7322008-07-27 06:49:38 +0900198 }
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900199 MultipleThreadMain::CleanUp();
initial.commit3f4a7322008-07-27 06:49:38 +0900200}
201
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900202// TODO(port): this test requires the MultipleLockThread class
203// (defined above), which requires the ability to pass file
204// descriptors between processes. We haven't done that yet in Chrome
205// for POSIX.
206#if defined(OS_WIN)
paulg@google.com78da6632008-09-11 09:31:43 +0900207// Create a set of threads to each open a shared memory segment and write to it
208// with the lock held. Verify that they are always reading/writing consistent
209// data.
initial.commit3f4a7322008-07-27 06:49:38 +0900210TEST(SharedMemoryTest, Lock) {
paulg@google.com78da6632008-09-11 09:31:43 +0900211 PlatformThreadHandle thread_handles[kNumThreads];
212 MultipleLockThread* thread_delegates[kNumThreads];
initial.commit3f4a7322008-07-27 06:49:38 +0900213
214 // Spawn the threads.
215 for (int index = 0; index < kNumThreads; ++index) {
paulg@google.com78da6632008-09-11 09:31:43 +0900216 PlatformThreadHandle pth;
217 thread_delegates[index] = new MultipleLockThread(index);
218 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
219 thread_handles[index] = pth;
initial.commit3f4a7322008-07-27 06:49:38 +0900220 }
221
222 // Wait for the threads to finish.
223 for (int index = 0; index < kNumThreads; ++index) {
paulg@google.com78da6632008-09-11 09:31:43 +0900224 PlatformThread::Join(thread_handles[index]);
225 delete thread_delegates[index];
initial.commit3f4a7322008-07-27 06:49:38 +0900226 }
227}
paulg@google.com78da6632008-09-11 09:31:43 +0900228#endif
brettw@google.comc60d9892008-11-14 12:25:15 +0900229
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900230// Allocate private (unique) shared memory with an empty string for a
231// name. Make sure several of them don't point to the same thing as
232// we might expect if the names are equal.
233TEST(SharedMemoryTest, AnonymousPrivate) {
234 int i, j;
235 int count = 4;
236 bool rv;
jam@chromium.orge74ca942010-02-17 08:58:27 +0900237 const uint32 kDataSize = 8192;
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900238
jrg@chromium.org81e22602009-02-06 04:04:34 +0900239 scoped_array<SharedMemory> memories(new SharedMemory[count]);
240 scoped_array<int*> pointers(new int*[count]);
241 ASSERT_TRUE(memories.get());
242 ASSERT_TRUE(pointers.get());
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900243
244 for (i = 0; i < count; i++) {
245 rv = memories[i].Create(L"", false, true, kDataSize);
246 EXPECT_TRUE(rv);
247 rv = memories[i].Map(kDataSize);
248 EXPECT_TRUE(rv);
249 int *ptr = static_cast<int*>(memories[i].memory());
250 EXPECT_TRUE(ptr);
251 pointers[i] = ptr;
252 }
253
254 for (i = 0; i < count; i++) {
255 // zero out the first int in each except for i; for that one, make it 100.
256 for (j = 0; j < count; j++) {
257 if (i == j)
258 pointers[j][0] = 100;
259 else
260 pointers[j][0] = 0;
261 }
262 // make sure there is no bleeding of the 100 into the other pointers
263 for (j = 0; j < count; j++) {
264 if (i == j)
265 EXPECT_EQ(100, pointers[j][0]);
266 else
267 EXPECT_EQ(0, pointers[j][0]);
268 }
269 }
270
271 for (int i = 0; i < count; i++) {
272 memories[i].Close();
273 }
jrg@chromium.org81e22602009-02-06 04:04:34 +0900274
275}
276
277
278// On POSIX it is especially important we test shmem across processes,
279// not just across threads. But the test is enabled on all platforms.
280class SharedMemoryProcessTest : public MultiProcessTest {
281 public:
282
283 static void CleanUp() {
284 SharedMemory memory;
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +0900285 memory.Delete(s_test_name_);
jrg@chromium.org81e22602009-02-06 04:04:34 +0900286 }
287
288 static int TaskTestMain() {
289 int errors = 0;
290 ScopedNSAutoreleasePool pool; // noop if not OSX
jam@chromium.orge74ca942010-02-17 08:58:27 +0900291 const uint32 kDataSize = 1024;
jrg@chromium.org81e22602009-02-06 04:04:34 +0900292 SharedMemory memory;
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +0900293 bool rv = memory.Create(s_test_name_, false, true, kDataSize);
jrg@chromium.org81e22602009-02-06 04:04:34 +0900294 EXPECT_TRUE(rv);
295 if (rv != true)
296 errors++;
297 rv = memory.Map(kDataSize);
298 EXPECT_TRUE(rv);
299 if (rv != true)
300 errors++;
301 int *ptr = static_cast<int*>(memory.memory());
302
303 for (int idx = 0; idx < 20; idx++) {
304 memory.Lock();
305 int i = (1 << 16) + idx;
306 *ptr = i;
307 PlatformThread::Sleep(10); // Short wait.
308 if (*ptr != i)
309 errors++;
310 memory.Unlock();
311 }
312
313 memory.Close();
314 return errors;
315 }
316
317 private:
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +0900318 static const wchar_t* const s_test_name_;
jrg@chromium.org81e22602009-02-06 04:04:34 +0900319};
320
maruel@chromium.orgf07658b2009-03-04 00:05:48 +0900321const wchar_t* const SharedMemoryProcessTest::s_test_name_ = L"MPMem";
jrg@chromium.org81e22602009-02-06 04:04:34 +0900322
323
324TEST_F(SharedMemoryProcessTest, Tasks) {
325 SharedMemoryProcessTest::CleanUp();
326
327 base::ProcessHandle handles[kNumTasks];
328 for (int index = 0; index < kNumTasks; ++index) {
329 handles[index] = SpawnChild(L"SharedMemoryTestMain");
330 }
331
332 int exit_code = 0;
333 for (int index = 0; index < kNumTasks; ++index) {
334 EXPECT_TRUE(base::WaitForExitCode(handles[index], &exit_code));
335 EXPECT_TRUE(exit_code == 0);
336 }
337
338 SharedMemoryProcessTest::CleanUp();
339}
340
341MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
342 return SharedMemoryProcessTest::TaskTestMain();
jrg@chromium.orgd505c3a2009-02-04 09:58:39 +0900343}
344
345
brettw@google.comc60d9892008-11-14 12:25:15 +0900346} // namespace base