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/test/multiprocess_test.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/time.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/multiprocess_func_list.h"
17 #if defined(OS_MACOSX)
18 #include "base/mac/scoped_nsautorelease_pool.h"
25 static const int kNumThreads
= 5;
26 static const int kNumTasks
= 5;
32 // Each thread will open the shared memory. Each thread will take a different 4
33 // byte int pointer, and keep changing it, with some small pauses in between.
34 // Verify that each thread's value in the shared memory is always correct.
35 class MultipleThreadMain
: public PlatformThread::Delegate
{
37 explicit MultipleThreadMain(int16 id
) : id_(id
) {}
38 virtual ~MultipleThreadMain() {}
40 static void CleanUp() {
42 memory
.Delete(s_test_name_
);
45 // PlatformThread::Delegate interface.
46 virtual void ThreadMain() OVERRIDE
{
47 #if defined(OS_MACOSX)
48 mac::ScopedNSAutoreleasePool pool
;
50 const uint32 kDataSize
= 1024;
52 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
54 rv
= memory
.Map(kDataSize
);
56 int *ptr
= static_cast<int*>(memory
.memory()) + id_
;
59 for (int idx
= 0; idx
< 100; idx
++) {
61 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
64 // Reset back to 0 for the next test that uses the same name.
73 static const char* const s_test_name_
;
75 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain
);
78 const char* const MultipleThreadMain::s_test_name_
=
79 "SharedMemoryOpenThreadTest";
82 // This test requires the ability to pass file descriptors between processes.
83 // We haven't done that yet in Chrome for POSIX.
85 // Each thread will open the shared memory. Each thread will take the memory,
86 // and keep changing it while trying to lock it, with some small pauses in
87 // between. Verify that each thread's value in the shared memory is always
89 class MultipleLockThread
: public PlatformThread::Delegate
{
91 explicit MultipleLockThread(int id
) : id_(id
) {}
92 virtual ~MultipleLockThread() {}
94 // PlatformThread::Delegate interface.
95 virtual void ThreadMain() OVERRIDE
{
96 const uint32 kDataSize
= sizeof(int);
97 SharedMemoryHandle handle
= NULL
;
100 EXPECT_TRUE(memory1
.CreateNamed("SharedMemoryMultipleLockThreadTest",
102 EXPECT_TRUE(memory1
.ShareToProcess(GetCurrentProcess(), &handle
));
103 // TODO(paulg): Implement this once we have a posix version of
104 // SharedMemory::ShareToProcess.
108 SharedMemory
memory2(handle
, false);
109 EXPECT_TRUE(memory2
.Map(kDataSize
));
110 volatile int* const ptr
= static_cast<int*>(memory2
.memory());
112 for (int idx
= 0; idx
< 20; idx
++) {
114 int i
= (id_
<< 16) + idx
;
116 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
127 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread
);
133 // Android doesn't support SharedMemory::Open/Delete/
134 // CreateNamed(openExisting=true)
135 #if !defined(OS_ANDROID)
136 TEST(SharedMemoryTest
, OpenClose
) {
137 const uint32 kDataSize
= 1024;
138 std::string test_name
= "SharedMemoryOpenCloseTest";
140 // Open two handles to a memory segment, confirm that they are mapped
141 // separately yet point to the same space.
142 SharedMemory memory1
;
143 bool rv
= memory1
.Delete(test_name
);
145 rv
= memory1
.Delete(test_name
);
147 rv
= memory1
.Open(test_name
, false);
149 rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
151 rv
= memory1
.Map(kDataSize
);
153 SharedMemory memory2
;
154 rv
= memory2
.Open(test_name
, false);
156 rv
= memory2
.Map(kDataSize
);
158 EXPECT_NE(memory1
.memory(), memory2
.memory()); // Compare the pointers.
160 // Make sure we don't segfault. (it actually happened!)
161 ASSERT_NE(memory1
.memory(), static_cast<void*>(NULL
));
162 ASSERT_NE(memory2
.memory(), static_cast<void*>(NULL
));
164 // Write data to the first memory segment, verify contents of second.
165 memset(memory1
.memory(), '1', kDataSize
);
166 EXPECT_EQ(memcmp(memory1
.memory(), memory2
.memory(), kDataSize
), 0);
168 // Close the first memory segment, and verify the second has the right data.
170 char *start_ptr
= static_cast<char *>(memory2
.memory());
171 char *end_ptr
= start_ptr
+ kDataSize
;
172 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++)
173 EXPECT_EQ(*ptr
, '1');
175 // Close the second memory segment.
178 rv
= memory1
.Delete(test_name
);
180 rv
= memory2
.Delete(test_name
);
184 TEST(SharedMemoryTest
, OpenExclusive
) {
185 const uint32 kDataSize
= 1024;
186 const uint32 kDataSize2
= 2048;
187 std::ostringstream test_name_stream
;
188 test_name_stream
<< "SharedMemoryOpenExclusiveTest."
189 << Time::Now().ToDoubleT();
190 std::string test_name
= test_name_stream
.str();
192 // Open two handles to a memory segment and check that open_existing works
194 SharedMemory memory1
;
195 bool rv
= memory1
.CreateNamed(test_name
, false, kDataSize
);
198 // Memory1 knows it's size because it created it.
199 EXPECT_EQ(memory1
.created_size(), kDataSize
);
201 rv
= memory1
.Map(kDataSize
);
204 memset(memory1
.memory(), 'G', kDataSize
);
206 SharedMemory memory2
;
207 // Should not be able to create if openExisting is false.
208 rv
= memory2
.CreateNamed(test_name
, false, kDataSize2
);
211 // Should be able to create with openExisting true.
212 rv
= memory2
.CreateNamed(test_name
, true, kDataSize2
);
215 // Memory2 shouldn't know the size because we didn't create it.
216 EXPECT_EQ(memory2
.created_size(), 0U);
218 // We should be able to map the original size.
219 rv
= memory2
.Map(kDataSize
);
222 // Verify that opening memory2 didn't truncate or delete memory 1.
223 char *start_ptr
= static_cast<char *>(memory2
.memory());
224 char *end_ptr
= start_ptr
+ kDataSize
;
225 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++) {
226 EXPECT_EQ(*ptr
, 'G');
232 rv
= memory1
.Delete(test_name
);
237 // Create a set of N threads to each open a shared memory segment and write to
238 // it. Verify that they are always reading/writing consistent data.
239 TEST(SharedMemoryTest
, MultipleThreads
) {
240 MultipleThreadMain::CleanUp();
241 // On POSIX we have a problem when 2 threads try to create the shmem
242 // (a file) at exactly the same time, since create both creates the
243 // file and zerofills it. We solve the problem for this unit test
244 // (make it not flaky) by starting with 1 thread, then
245 // intentionally don't clean up its shmem before running with
248 int threadcounts
[] = { 1, kNumThreads
};
249 for (size_t i
= 0; i
< arraysize(threadcounts
); i
++) {
250 int numthreads
= threadcounts
[i
];
251 scoped_array
<PlatformThreadHandle
> thread_handles
;
252 scoped_array
<MultipleThreadMain
*> thread_delegates
;
254 thread_handles
.reset(new PlatformThreadHandle
[numthreads
]);
255 thread_delegates
.reset(new MultipleThreadMain
*[numthreads
]);
257 // Spawn the threads.
258 for (int16 index
= 0; index
< numthreads
; index
++) {
259 PlatformThreadHandle pth
;
260 thread_delegates
[index
] = new MultipleThreadMain(index
);
261 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
262 thread_handles
[index
] = pth
;
265 // Wait for the threads to finish.
266 for (int index
= 0; index
< numthreads
; index
++) {
267 PlatformThread::Join(thread_handles
[index
]);
268 delete thread_delegates
[index
];
271 MultipleThreadMain::CleanUp();
274 // TODO(port): this test requires the MultipleLockThread class
275 // (defined above), which requires the ability to pass file
276 // descriptors between processes. We haven't done that yet in Chrome
279 // Create a set of threads to each open a shared memory segment and write to it
280 // with the lock held. Verify that they are always reading/writing consistent
282 TEST(SharedMemoryTest
, Lock
) {
283 PlatformThreadHandle thread_handles
[kNumThreads
];
284 MultipleLockThread
* thread_delegates
[kNumThreads
];
286 // Spawn the threads.
287 for (int index
= 0; index
< kNumThreads
; ++index
) {
288 PlatformThreadHandle pth
;
289 thread_delegates
[index
] = new MultipleLockThread(index
);
290 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
291 thread_handles
[index
] = pth
;
294 // Wait for the threads to finish.
295 for (int index
= 0; index
< kNumThreads
; ++index
) {
296 PlatformThread::Join(thread_handles
[index
]);
297 delete thread_delegates
[index
];
302 // Allocate private (unique) shared memory with an empty string for a
303 // name. Make sure several of them don't point to the same thing as
304 // we might expect if the names are equal.
305 TEST(SharedMemoryTest
, AnonymousPrivate
) {
309 const uint32 kDataSize
= 8192;
311 scoped_array
<SharedMemory
> memories(new SharedMemory
[count
]);
312 scoped_array
<int*> pointers(new int*[count
]);
313 ASSERT_TRUE(memories
.get());
314 ASSERT_TRUE(pointers
.get());
316 for (i
= 0; i
< count
; i
++) {
317 rv
= memories
[i
].CreateAndMapAnonymous(kDataSize
);
319 int *ptr
= static_cast<int*>(memories
[i
].memory());
324 for (i
= 0; i
< count
; i
++) {
325 // zero out the first int in each except for i; for that one, make it 100.
326 for (j
= 0; j
< count
; j
++) {
328 pointers
[j
][0] = 100;
332 // make sure there is no bleeding of the 100 into the other pointers
333 for (j
= 0; j
< count
; j
++) {
335 EXPECT_EQ(100, pointers
[j
][0]);
337 EXPECT_EQ(0, pointers
[j
][0]);
341 for (int i
= 0; i
< count
; i
++) {
346 #if defined(OS_POSIX)
347 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
348 TEST(SharedMemoryTest
, AnonymousExecutable
) {
349 const uint32 kTestSize
= 1 << 16;
351 SharedMemory shared_memory
;
352 SharedMemoryCreateOptions options
;
353 options
.size
= kTestSize
;
354 options
.executable
= true;
356 EXPECT_TRUE(shared_memory
.Create(options
));
357 EXPECT_TRUE(shared_memory
.Map(shared_memory
.created_size()));
359 EXPECT_EQ(0, mprotect(shared_memory
.memory(), shared_memory
.created_size(),
360 PROT_READ
| PROT_EXEC
));
364 // Map() will return addresses which are aligned to the platform page size, this
365 // varies from platform to platform though. Since we'd like to advertise a
366 // minimum alignment that callers can count on, test for it here.
367 TEST(SharedMemoryTest
, MapMinimumAlignment
) {
368 static const int kDataSize
= 8192;
370 SharedMemory shared_memory
;
371 ASSERT_TRUE(shared_memory
.CreateAndMapAnonymous(kDataSize
));
372 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
373 shared_memory
.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
374 shared_memory
.Close();
377 #if !defined(OS_IOS) // iOS does not allow multiple processes.
379 // On POSIX it is especially important we test shmem across processes,
380 // not just across threads. But the test is enabled on all platforms.
381 class SharedMemoryProcessTest
: public MultiProcessTest
{
384 static void CleanUp() {
386 memory
.Delete(s_test_name_
);
389 static int TaskTestMain() {
391 #if defined(OS_MACOSX)
392 mac::ScopedNSAutoreleasePool pool
;
394 const uint32 kDataSize
= 1024;
396 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
400 rv
= memory
.Map(kDataSize
);
404 int *ptr
= static_cast<int*>(memory
.memory());
406 for (int idx
= 0; idx
< 20; idx
++) {
408 int i
= (1 << 16) + idx
;
410 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
421 static const char* const s_test_name_
;
424 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
426 TEST_F(SharedMemoryProcessTest
, Tasks
) {
427 SharedMemoryProcessTest::CleanUp();
429 ProcessHandle handles
[kNumTasks
];
430 for (int index
= 0; index
< kNumTasks
; ++index
) {
431 handles
[index
] = SpawnChild("SharedMemoryTestMain", false);
432 ASSERT_TRUE(handles
[index
]);
436 for (int index
= 0; index
< kNumTasks
; ++index
) {
437 EXPECT_TRUE(WaitForExitCode(handles
[index
], &exit_code
));
438 EXPECT_EQ(0, exit_code
);
441 SharedMemoryProcessTest::CleanUp();
444 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
445 return SharedMemoryProcessTest::TaskTestMain();