1 // Copyright (c) 2011 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.
5 #include "base/basictypes.h"
6 #include "base/mac/scoped_nsautorelease_pool.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/shared_memory.h"
9 #include "base/test/multiprocess_test.h"
10 #include "base/threading/platform_thread.h"
11 #include "base/time.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "testing/multiprocess_func_list.h"
15 static const int kNumThreads
= 5;
16 static const int kNumTasks
= 5;
22 // Each thread will open the shared memory. Each thread will take a different 4
23 // byte int pointer, and keep changing it, with some small pauses in between.
24 // Verify that each thread's value in the shared memory is always correct.
25 class MultipleThreadMain
: public PlatformThread::Delegate
{
27 explicit MultipleThreadMain(int16 id
) : id_(id
) {}
28 ~MultipleThreadMain() {}
30 static void CleanUp() {
32 memory
.Delete(s_test_name_
);
35 // PlatformThread::Delegate interface.
37 mac::ScopedNSAutoreleasePool pool
; // noop if not OSX
38 const uint32 kDataSize
= 1024;
40 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
42 rv
= memory
.Map(kDataSize
);
44 int *ptr
= static_cast<int*>(memory
.memory()) + id_
;
47 for (int idx
= 0; idx
< 100; idx
++) {
49 PlatformThread::Sleep(1); // Short wait.
52 // Reset back to 0 for the next test that uses the same name.
61 static const char* const s_test_name_
;
63 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain
);
66 const char* const MultipleThreadMain::s_test_name_
=
67 "SharedMemoryOpenThreadTest";
70 // This test requires the ability to pass file descriptors between processes.
71 // We haven't done that yet in Chrome for POSIX.
73 // Each thread will open the shared memory. Each thread will take the memory,
74 // and keep changing it while trying to lock it, with some small pauses in
75 // between. Verify that each thread's value in the shared memory is always
77 class MultipleLockThread
: public PlatformThread::Delegate
{
79 explicit MultipleLockThread(int id
) : id_(id
) {}
80 ~MultipleLockThread() {}
82 // PlatformThread::Delegate interface.
84 const uint32 kDataSize
= sizeof(int);
85 SharedMemoryHandle handle
= NULL
;
88 EXPECT_TRUE(memory1
.CreateNamed("SharedMemoryMultipleLockThreadTest",
90 EXPECT_TRUE(memory1
.ShareToProcess(GetCurrentProcess(), &handle
));
91 // TODO(paulg): Implement this once we have a posix version of
92 // SharedMemory::ShareToProcess.
96 SharedMemory
memory2(handle
, false);
97 EXPECT_TRUE(memory2
.Map(kDataSize
));
98 volatile int* const ptr
= static_cast<int*>(memory2
.memory());
100 for (int idx
= 0; idx
< 20; idx
++) {
102 int i
= (id_
<< 16) + idx
;
104 PlatformThread::Sleep(1); // Short wait.
115 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread
);
121 TEST(SharedMemoryTest
, OpenClose
) {
122 const uint32 kDataSize
= 1024;
123 std::string test_name
= "SharedMemoryOpenCloseTest";
125 // Open two handles to a memory segment, confirm that they are mapped
126 // separately yet point to the same space.
127 SharedMemory memory1
;
128 bool rv
= memory1
.Delete(test_name
);
130 rv
= memory1
.Delete(test_name
);
132 rv
= memory1
.Open(test_name
, false);
134 rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
136 rv
= memory1
.Map(kDataSize
);
138 SharedMemory memory2
;
139 rv
= memory2
.Open(test_name
, false);
141 rv
= memory2
.Map(kDataSize
);
143 EXPECT_NE(memory1
.memory(), memory2
.memory()); // Compare the pointers.
145 // Make sure we don't segfault. (it actually happened!)
146 ASSERT_NE(memory1
.memory(), static_cast<void*>(NULL
));
147 ASSERT_NE(memory2
.memory(), static_cast<void*>(NULL
));
149 // Write data to the first memory segment, verify contents of second.
150 memset(memory1
.memory(), '1', kDataSize
);
151 EXPECT_EQ(memcmp(memory1
.memory(), memory2
.memory(), kDataSize
), 0);
153 // Close the first memory segment, and verify the second has the right data.
155 char *start_ptr
= static_cast<char *>(memory2
.memory());
156 char *end_ptr
= start_ptr
+ kDataSize
;
157 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++)
158 EXPECT_EQ(*ptr
, '1');
160 // Close the second memory segment.
163 rv
= memory1
.Delete(test_name
);
165 rv
= memory2
.Delete(test_name
);
169 TEST(SharedMemoryTest
, OpenExclusive
) {
170 const uint32 kDataSize
= 1024;
171 const uint32 kDataSize2
= 2048;
172 std::ostringstream test_name_stream
;
173 test_name_stream
<< "SharedMemoryOpenExclusiveTest."
174 << Time::Now().ToDoubleT();
175 std::string test_name
= test_name_stream
.str();
177 // Open two handles to a memory segment and check that open_existing works
179 SharedMemory memory1
;
180 bool rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
183 // Memory1 knows it's size because it created it.
184 EXPECT_EQ(memory1
.created_size(), kDataSize
);
186 rv
= memory1
.Map(kDataSize
);
189 memset(memory1
.memory(), 'G', kDataSize
);
191 SharedMemory memory2
;
192 // Should not be able to create if openExisting is false.
193 rv
= memory2
.CreateNamed(test_name
, false, kDataSize2
);
196 // Should be able to create with openExisting true.
197 rv
= memory2
.CreateNamed(test_name
, true, kDataSize2
);
200 // Memory2 shouldn't know the size because we didn't create it.
201 EXPECT_EQ(memory2
.created_size(), 0U);
203 // We should be able to map the original size.
204 rv
= memory2
.Map(kDataSize
);
207 // Verify that opening memory2 didn't truncate or delete memory 1.
208 char *start_ptr
= static_cast<char *>(memory2
.memory());
209 char *end_ptr
= start_ptr
+ kDataSize
;
210 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++) {
211 EXPECT_EQ(*ptr
, 'G');
217 rv
= memory1
.Delete(test_name
);
221 // Create a set of N threads to each open a shared memory segment and write to
222 // it. Verify that they are always reading/writing consistent data.
223 TEST(SharedMemoryTest
, MultipleThreads
) {
224 MultipleThreadMain::CleanUp();
225 // On POSIX we have a problem when 2 threads try to create the shmem
226 // (a file) at exactly the same time, since create both creates the
227 // file and zerofills it. We solve the problem for this unit test
228 // (make it not flaky) by starting with 1 thread, then
229 // intentionally don't clean up its shmem before running with
232 int threadcounts
[] = { 1, kNumThreads
};
233 for (size_t i
= 0; i
< arraysize(threadcounts
); i
++) {
234 int numthreads
= threadcounts
[i
];
235 scoped_array
<PlatformThreadHandle
> thread_handles
;
236 scoped_array
<MultipleThreadMain
*> thread_delegates
;
238 thread_handles
.reset(new PlatformThreadHandle
[numthreads
]);
239 thread_delegates
.reset(new MultipleThreadMain
*[numthreads
]);
241 // Spawn the threads.
242 for (int16 index
= 0; index
< numthreads
; index
++) {
243 PlatformThreadHandle pth
;
244 thread_delegates
[index
] = new MultipleThreadMain(index
);
245 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
246 thread_handles
[index
] = pth
;
249 // Wait for the threads to finish.
250 for (int index
= 0; index
< numthreads
; index
++) {
251 PlatformThread::Join(thread_handles
[index
]);
252 delete thread_delegates
[index
];
255 MultipleThreadMain::CleanUp();
258 // TODO(port): this test requires the MultipleLockThread class
259 // (defined above), which requires the ability to pass file
260 // descriptors between processes. We haven't done that yet in Chrome
263 // Create a set of threads to each open a shared memory segment and write to it
264 // with the lock held. Verify that they are always reading/writing consistent
266 TEST(SharedMemoryTest
, Lock
) {
267 PlatformThreadHandle thread_handles
[kNumThreads
];
268 MultipleLockThread
* thread_delegates
[kNumThreads
];
270 // Spawn the threads.
271 for (int index
= 0; index
< kNumThreads
; ++index
) {
272 PlatformThreadHandle pth
;
273 thread_delegates
[index
] = new MultipleLockThread(index
);
274 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
275 thread_handles
[index
] = pth
;
278 // Wait for the threads to finish.
279 for (int index
= 0; index
< kNumThreads
; ++index
) {
280 PlatformThread::Join(thread_handles
[index
]);
281 delete thread_delegates
[index
];
286 // Allocate private (unique) shared memory with an empty string for a
287 // name. Make sure several of them don't point to the same thing as
288 // we might expect if the names are equal.
289 TEST(SharedMemoryTest
, AnonymousPrivate
) {
293 const uint32 kDataSize
= 8192;
295 scoped_array
<SharedMemory
> memories(new SharedMemory
[count
]);
296 scoped_array
<int*> pointers(new int*[count
]);
297 ASSERT_TRUE(memories
.get());
298 ASSERT_TRUE(pointers
.get());
300 for (i
= 0; i
< count
; i
++) {
301 rv
= memories
[i
].CreateAndMapAnonymous(kDataSize
);
303 int *ptr
= static_cast<int*>(memories
[i
].memory());
308 for (i
= 0; i
< count
; i
++) {
309 // zero out the first int in each except for i; for that one, make it 100.
310 for (j
= 0; j
< count
; j
++) {
312 pointers
[j
][0] = 100;
316 // make sure there is no bleeding of the 100 into the other pointers
317 for (j
= 0; j
< count
; j
++) {
319 EXPECT_EQ(100, pointers
[j
][0]);
321 EXPECT_EQ(0, pointers
[j
][0]);
325 for (int i
= 0; i
< count
; i
++) {
330 // On POSIX it is especially important we test shmem across processes,
331 // not just across threads. But the test is enabled on all platforms.
332 class SharedMemoryProcessTest
: public MultiProcessTest
{
335 static void CleanUp() {
337 memory
.Delete(s_test_name_
);
340 static int TaskTestMain() {
342 mac::ScopedNSAutoreleasePool pool
; // noop if not OSX
343 const uint32 kDataSize
= 1024;
345 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
349 rv
= memory
.Map(kDataSize
);
353 int *ptr
= static_cast<int*>(memory
.memory());
355 for (int idx
= 0; idx
< 20; idx
++) {
357 int i
= (1 << 16) + idx
;
359 PlatformThread::Sleep(10); // Short wait.
370 static const char* const s_test_name_
;
373 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
376 #if defined(OS_MACOSX)
377 #define MAYBE_Tasks FLAKY_Tasks
379 #define MAYBE_Tasks Tasks
382 TEST_F(SharedMemoryProcessTest
, MAYBE_Tasks
) {
383 SharedMemoryProcessTest::CleanUp();
385 ProcessHandle handles
[kNumTasks
];
386 for (int index
= 0; index
< kNumTasks
; ++index
) {
387 handles
[index
] = SpawnChild("SharedMemoryTestMain", false);
388 ASSERT_TRUE(handles
[index
]);
392 for (int index
= 0; index
< kNumTasks
; ++index
) {
393 EXPECT_TRUE(WaitForExitCode(handles
[index
], &exit_code
));
394 EXPECT_TRUE(exit_code
== 0);
397 SharedMemoryProcessTest::CleanUp();
400 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
401 return SharedMemoryProcessTest::TaskTestMain();