1 // Copyright (c) 2012 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"
7 #include "base/mac/scoped_nsautorelease_pool.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/shared_memory.h"
11 #include "base/sys_info.h"
12 #include "base/test/multiprocess_test.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/multiprocess_func_list.h"
18 #if defined(OS_MACOSX)
19 #include "base/mac/scoped_nsautorelease_pool.h"
26 static const int kNumThreads
= 5;
27 static const int kNumTasks
= 5;
33 // Each thread will open the shared memory. Each thread will take a different 4
34 // byte int pointer, and keep changing it, with some small pauses in between.
35 // Verify that each thread's value in the shared memory is always correct.
36 class MultipleThreadMain
: public PlatformThread::Delegate
{
38 explicit MultipleThreadMain(int16 id
) : id_(id
) {}
39 virtual ~MultipleThreadMain() {}
41 static void CleanUp() {
43 memory
.Delete(s_test_name_
);
46 // PlatformThread::Delegate interface.
47 virtual void ThreadMain() OVERRIDE
{
48 #if defined(OS_MACOSX)
49 mac::ScopedNSAutoreleasePool pool
;
51 const uint32 kDataSize
= 1024;
53 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
55 rv
= memory
.Map(kDataSize
);
57 int *ptr
= static_cast<int*>(memory
.memory()) + id_
;
60 for (int idx
= 0; idx
< 100; idx
++) {
62 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
65 // Reset back to 0 for the next test that uses the same name.
74 static const char* const s_test_name_
;
76 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain
);
79 const char* const MultipleThreadMain::s_test_name_
=
80 "SharedMemoryOpenThreadTest";
83 // This test requires the ability to pass file descriptors between processes.
84 // We haven't done that yet in Chrome for POSIX.
86 // Each thread will open the shared memory. Each thread will take the memory,
87 // and keep changing it while trying to lock it, with some small pauses in
88 // between. Verify that each thread's value in the shared memory is always
90 class MultipleLockThread
: public PlatformThread::Delegate
{
92 explicit MultipleLockThread(int id
) : id_(id
) {}
93 virtual ~MultipleLockThread() {}
95 // PlatformThread::Delegate interface.
96 virtual void ThreadMain() OVERRIDE
{
97 const uint32 kDataSize
= sizeof(int);
98 SharedMemoryHandle handle
= NULL
;
100 SharedMemory memory1
;
101 EXPECT_TRUE(memory1
.CreateNamed("SharedMemoryMultipleLockThreadTest",
103 EXPECT_TRUE(memory1
.ShareToProcess(GetCurrentProcess(), &handle
));
104 // TODO(paulg): Implement this once we have a posix version of
105 // SharedMemory::ShareToProcess.
109 SharedMemory
memory2(handle
, false);
110 EXPECT_TRUE(memory2
.Map(kDataSize
));
111 volatile int* const ptr
= static_cast<int*>(memory2
.memory());
113 for (int idx
= 0; idx
< 20; idx
++) {
115 int i
= (id_
<< 16) + idx
;
117 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
128 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread
);
134 // Android doesn't support SharedMemory::Open/Delete/
135 // CreateNamed(openExisting=true)
136 #if !defined(OS_ANDROID)
137 TEST(SharedMemoryTest
, OpenClose
) {
138 const uint32 kDataSize
= 1024;
139 std::string test_name
= "SharedMemoryOpenCloseTest";
141 // Open two handles to a memory segment, confirm that they are mapped
142 // separately yet point to the same space.
143 SharedMemory memory1
;
144 bool rv
= memory1
.Delete(test_name
);
146 rv
= memory1
.Delete(test_name
);
148 rv
= memory1
.Open(test_name
, false);
150 rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
152 rv
= memory1
.Map(kDataSize
);
154 SharedMemory memory2
;
155 rv
= memory2
.Open(test_name
, false);
157 rv
= memory2
.Map(kDataSize
);
159 EXPECT_NE(memory1
.memory(), memory2
.memory()); // Compare the pointers.
161 // Make sure we don't segfault. (it actually happened!)
162 ASSERT_NE(memory1
.memory(), static_cast<void*>(NULL
));
163 ASSERT_NE(memory2
.memory(), static_cast<void*>(NULL
));
165 // Write data to the first memory segment, verify contents of second.
166 memset(memory1
.memory(), '1', kDataSize
);
167 EXPECT_EQ(memcmp(memory1
.memory(), memory2
.memory(), kDataSize
), 0);
169 // Close the first memory segment, and verify the second has the right data.
171 char *start_ptr
= static_cast<char *>(memory2
.memory());
172 char *end_ptr
= start_ptr
+ kDataSize
;
173 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++)
174 EXPECT_EQ(*ptr
, '1');
176 // Close the second memory segment.
179 rv
= memory1
.Delete(test_name
);
181 rv
= memory2
.Delete(test_name
);
185 TEST(SharedMemoryTest
, OpenExclusive
) {
186 const uint32 kDataSize
= 1024;
187 const uint32 kDataSize2
= 2048;
188 std::ostringstream test_name_stream
;
189 test_name_stream
<< "SharedMemoryOpenExclusiveTest."
190 << Time::Now().ToDoubleT();
191 std::string test_name
= test_name_stream
.str();
193 // Open two handles to a memory segment and check that open_existing works
195 SharedMemory memory1
;
196 bool rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
199 // Memory1 knows it's size because it created it.
200 EXPECT_EQ(memory1
.created_size(), kDataSize
);
202 rv
= memory1
.Map(kDataSize
);
205 memset(memory1
.memory(), 'G', kDataSize
);
207 SharedMemory memory2
;
208 // Should not be able to create if openExisting is false.
209 rv
= memory2
.CreateNamed(test_name
, false, kDataSize2
);
212 // Should be able to create with openExisting true.
213 rv
= memory2
.CreateNamed(test_name
, true, kDataSize2
);
216 // Memory2 shouldn't know the size because we didn't create it.
217 EXPECT_EQ(memory2
.created_size(), 0U);
219 // We should be able to map the original size.
220 rv
= memory2
.Map(kDataSize
);
223 // Verify that opening memory2 didn't truncate or delete memory 1.
224 char *start_ptr
= static_cast<char *>(memory2
.memory());
225 char *end_ptr
= start_ptr
+ kDataSize
;
226 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++) {
227 EXPECT_EQ(*ptr
, 'G');
233 rv
= memory1
.Delete(test_name
);
238 // Create a set of N threads to each open a shared memory segment and write to
239 // it. Verify that they are always reading/writing consistent data.
240 TEST(SharedMemoryTest
, MultipleThreads
) {
241 MultipleThreadMain::CleanUp();
242 // On POSIX we have a problem when 2 threads try to create the shmem
243 // (a file) at exactly the same time, since create both creates the
244 // file and zerofills it. We solve the problem for this unit test
245 // (make it not flaky) by starting with 1 thread, then
246 // intentionally don't clean up its shmem before running with
249 int threadcounts
[] = { 1, kNumThreads
};
250 for (size_t i
= 0; i
< arraysize(threadcounts
); i
++) {
251 int numthreads
= threadcounts
[i
];
252 scoped_ptr
<PlatformThreadHandle
[]> thread_handles
;
253 scoped_ptr
<MultipleThreadMain
*[]> thread_delegates
;
255 thread_handles
.reset(new PlatformThreadHandle
[numthreads
]);
256 thread_delegates
.reset(new MultipleThreadMain
*[numthreads
]);
258 // Spawn the threads.
259 for (int16 index
= 0; index
< numthreads
; index
++) {
260 PlatformThreadHandle pth
;
261 thread_delegates
[index
] = new MultipleThreadMain(index
);
262 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
263 thread_handles
[index
] = pth
;
266 // Wait for the threads to finish.
267 for (int index
= 0; index
< numthreads
; index
++) {
268 PlatformThread::Join(thread_handles
[index
]);
269 delete thread_delegates
[index
];
272 MultipleThreadMain::CleanUp();
275 // TODO(port): this test requires the MultipleLockThread class
276 // (defined above), which requires the ability to pass file
277 // descriptors between processes. We haven't done that yet in Chrome
280 // Create a set of threads to each open a shared memory segment and write to it
281 // with the lock held. Verify that they are always reading/writing consistent
283 TEST(SharedMemoryTest
, Lock
) {
284 PlatformThreadHandle thread_handles
[kNumThreads
];
285 MultipleLockThread
* thread_delegates
[kNumThreads
];
287 // Spawn the threads.
288 for (int index
= 0; index
< kNumThreads
; ++index
) {
289 PlatformThreadHandle pth
;
290 thread_delegates
[index
] = new MultipleLockThread(index
);
291 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
292 thread_handles
[index
] = pth
;
295 // Wait for the threads to finish.
296 for (int index
= 0; index
< kNumThreads
; ++index
) {
297 PlatformThread::Join(thread_handles
[index
]);
298 delete thread_delegates
[index
];
303 // Allocate private (unique) shared memory with an empty string for a
304 // name. Make sure several of them don't point to the same thing as
305 // we might expect if the names are equal.
306 TEST(SharedMemoryTest
, AnonymousPrivate
) {
310 const uint32 kDataSize
= 8192;
312 scoped_ptr
<SharedMemory
[]> memories(new SharedMemory
[count
]);
313 scoped_ptr
<int*[]> pointers(new int*[count
]);
314 ASSERT_TRUE(memories
.get());
315 ASSERT_TRUE(pointers
.get());
317 for (i
= 0; i
< count
; i
++) {
318 rv
= memories
[i
].CreateAndMapAnonymous(kDataSize
);
320 int *ptr
= static_cast<int*>(memories
[i
].memory());
325 for (i
= 0; i
< count
; i
++) {
326 // zero out the first int in each except for i; for that one, make it 100.
327 for (j
= 0; j
< count
; j
++) {
329 pointers
[j
][0] = 100;
333 // make sure there is no bleeding of the 100 into the other pointers
334 for (j
= 0; j
< count
; j
++) {
336 EXPECT_EQ(100, pointers
[j
][0]);
338 EXPECT_EQ(0, pointers
[j
][0]);
342 for (int i
= 0; i
< count
; i
++) {
347 TEST(SharedMemoryTest
, MapAt
) {
348 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32
));
349 const size_t kCount
= SysInfo::VMAllocationGranularity();
350 const size_t kDataSize
= kCount
* sizeof(uint32
);
353 ASSERT_TRUE(memory
.CreateAndMapAnonymous(kDataSize
));
354 ASSERT_TRUE(memory
.Map(kDataSize
));
355 uint32
* ptr
= static_cast<uint32
*>(memory
.memory());
356 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
358 for (size_t i
= 0; i
< kCount
; ++i
) {
364 off_t offset
= SysInfo::VMAllocationGranularity();
365 ASSERT_TRUE(memory
.MapAt(offset
, kDataSize
- offset
));
366 offset
/= sizeof(uint32
);
367 ptr
= static_cast<uint32
*>(memory
.memory());
368 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
369 for (size_t i
= offset
; i
< kCount
; ++i
) {
370 EXPECT_EQ(ptr
[i
- offset
], i
);
374 #if defined(OS_POSIX)
375 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
376 TEST(SharedMemoryTest
, AnonymousExecutable
) {
377 const uint32 kTestSize
= 1 << 16;
379 SharedMemory shared_memory
;
380 SharedMemoryCreateOptions options
;
381 options
.size
= kTestSize
;
382 options
.executable
= true;
384 EXPECT_TRUE(shared_memory
.Create(options
));
385 EXPECT_TRUE(shared_memory
.Map(shared_memory
.created_size()));
387 EXPECT_EQ(0, mprotect(shared_memory
.memory(), shared_memory
.created_size(),
388 PROT_READ
| PROT_EXEC
));
392 // Map() will return addresses which are aligned to the platform page size, this
393 // varies from platform to platform though. Since we'd like to advertise a
394 // minimum alignment that callers can count on, test for it here.
395 TEST(SharedMemoryTest
, MapMinimumAlignment
) {
396 static const int kDataSize
= 8192;
398 SharedMemory shared_memory
;
399 ASSERT_TRUE(shared_memory
.CreateAndMapAnonymous(kDataSize
));
400 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
401 shared_memory
.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
402 shared_memory
.Close();
405 #if !defined(OS_IOS) // iOS does not allow multiple processes.
407 // On POSIX it is especially important we test shmem across processes,
408 // not just across threads. But the test is enabled on all platforms.
409 class SharedMemoryProcessTest
: public MultiProcessTest
{
412 static void CleanUp() {
414 memory
.Delete(s_test_name_
);
417 static int TaskTestMain() {
419 #if defined(OS_MACOSX)
420 mac::ScopedNSAutoreleasePool pool
;
422 const uint32 kDataSize
= 1024;
424 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
428 rv
= memory
.Map(kDataSize
);
432 int *ptr
= static_cast<int*>(memory
.memory());
434 for (int idx
= 0; idx
< 20; idx
++) {
436 int i
= (1 << 16) + idx
;
438 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
449 static const char* const s_test_name_
;
452 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
454 TEST_F(SharedMemoryProcessTest
, Tasks
) {
455 SharedMemoryProcessTest::CleanUp();
457 ProcessHandle handles
[kNumTasks
];
458 for (int index
= 0; index
< kNumTasks
; ++index
) {
459 handles
[index
] = SpawnChild("SharedMemoryTestMain", false);
460 ASSERT_TRUE(handles
[index
]);
464 for (int index
= 0; index
< kNumTasks
; ++index
) {
465 EXPECT_TRUE(WaitForExitCode(handles
[index
], &exit_code
));
466 EXPECT_EQ(0, exit_code
);
469 SharedMemoryProcessTest::CleanUp();
472 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
473 return SharedMemoryProcessTest::TaskTestMain();