Create an initial chrome://supervised-user-internals page
[chromium-blink-merge.git] / base / memory / shared_memory_unittest.cc
blobc129e18d4c3049961ee1462cb93870c2485e594e
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/atomicops.h"
6 #include "base/basictypes.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/memory/shared_memory.h"
9 #include "base/process/kill.h"
10 #include "base/rand_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/sys_info.h"
13 #include "base/test/multiprocess_test.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/time/time.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/multiprocess_func_list.h"
19 #if defined(OS_MACOSX)
20 #include "base/mac/scoped_nsautorelease_pool.h"
21 #endif
23 #if defined(OS_POSIX)
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #endif
32 #if defined(OS_WIN)
33 #include "base/win/scoped_handle.h"
34 #endif
36 static const int kNumThreads = 5;
37 #if !defined(OS_IOS) && !defined(OS_ANDROID)
38 static const int kNumTasks = 5;
39 #endif
41 namespace base {
43 namespace {
45 // Each thread will open the shared memory. Each thread will take a different 4
46 // byte int pointer, and keep changing it, with some small pauses in between.
47 // Verify that each thread's value in the shared memory is always correct.
48 class MultipleThreadMain : public PlatformThread::Delegate {
49 public:
50 explicit MultipleThreadMain(int16 id) : id_(id) {}
51 ~MultipleThreadMain() override {}
53 static void CleanUp() {
54 SharedMemory memory;
55 memory.Delete(s_test_name_);
58 // PlatformThread::Delegate interface.
59 void ThreadMain() override {
60 #if defined(OS_MACOSX)
61 mac::ScopedNSAutoreleasePool pool;
62 #endif
63 const uint32 kDataSize = 1024;
64 SharedMemory memory;
65 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
66 EXPECT_TRUE(rv);
67 rv = memory.Map(kDataSize);
68 EXPECT_TRUE(rv);
69 int *ptr = static_cast<int*>(memory.memory()) + id_;
70 EXPECT_EQ(0, *ptr);
72 for (int idx = 0; idx < 100; idx++) {
73 *ptr = idx;
74 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
75 EXPECT_EQ(*ptr, idx);
77 // Reset back to 0 for the next test that uses the same name.
78 *ptr = 0;
80 memory.Close();
83 private:
84 int16 id_;
86 static const char* const s_test_name_;
88 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
91 const char* const MultipleThreadMain::s_test_name_ =
92 "SharedMemoryOpenThreadTest";
94 } // namespace
96 // Android doesn't support SharedMemory::Open/Delete/
97 // CreateNamedDeprecated(openExisting=true)
98 #if !defined(OS_ANDROID)
99 TEST(SharedMemoryTest, OpenClose) {
100 const uint32 kDataSize = 1024;
101 std::string test_name = "SharedMemoryOpenCloseTest";
103 // Open two handles to a memory segment, confirm that they are mapped
104 // separately yet point to the same space.
105 SharedMemory memory1;
106 bool rv = memory1.Delete(test_name);
107 EXPECT_TRUE(rv);
108 rv = memory1.Delete(test_name);
109 EXPECT_TRUE(rv);
110 rv = memory1.Open(test_name, false);
111 EXPECT_FALSE(rv);
112 rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
113 EXPECT_TRUE(rv);
114 rv = memory1.Map(kDataSize);
115 EXPECT_TRUE(rv);
116 SharedMemory memory2;
117 rv = memory2.Open(test_name, false);
118 EXPECT_TRUE(rv);
119 rv = memory2.Map(kDataSize);
120 EXPECT_TRUE(rv);
121 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers.
123 // Make sure we don't segfault. (it actually happened!)
124 ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
125 ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
127 // Write data to the first memory segment, verify contents of second.
128 memset(memory1.memory(), '1', kDataSize);
129 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
131 // Close the first memory segment, and verify the second has the right data.
132 memory1.Close();
133 char *start_ptr = static_cast<char *>(memory2.memory());
134 char *end_ptr = start_ptr + kDataSize;
135 for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
136 EXPECT_EQ(*ptr, '1');
138 // Close the second memory segment.
139 memory2.Close();
141 rv = memory1.Delete(test_name);
142 EXPECT_TRUE(rv);
143 rv = memory2.Delete(test_name);
144 EXPECT_TRUE(rv);
147 TEST(SharedMemoryTest, OpenExclusive) {
148 const uint32 kDataSize = 1024;
149 const uint32 kDataSize2 = 2048;
150 std::ostringstream test_name_stream;
151 test_name_stream << "SharedMemoryOpenExclusiveTest."
152 << Time::Now().ToDoubleT();
153 std::string test_name = test_name_stream.str();
155 // Open two handles to a memory segment and check that
156 // open_existing_deprecated works as expected.
157 SharedMemory memory1;
158 bool rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
159 EXPECT_TRUE(rv);
161 // Memory1 knows it's size because it created it.
162 EXPECT_EQ(memory1.requested_size(), kDataSize);
164 rv = memory1.Map(kDataSize);
165 EXPECT_TRUE(rv);
167 // The mapped memory1 must be at least the size we asked for.
168 EXPECT_GE(memory1.mapped_size(), kDataSize);
170 // The mapped memory1 shouldn't exceed rounding for allocation granularity.
171 EXPECT_LT(memory1.mapped_size(),
172 kDataSize + base::SysInfo::VMAllocationGranularity());
174 memset(memory1.memory(), 'G', kDataSize);
176 SharedMemory memory2;
177 // Should not be able to create if openExisting is false.
178 rv = memory2.CreateNamedDeprecated(test_name, false, kDataSize2);
179 EXPECT_FALSE(rv);
181 // Should be able to create with openExisting true.
182 rv = memory2.CreateNamedDeprecated(test_name, true, kDataSize2);
183 EXPECT_TRUE(rv);
185 // Memory2 shouldn't know the size because we didn't create it.
186 EXPECT_EQ(memory2.requested_size(), 0U);
188 // We should be able to map the original size.
189 rv = memory2.Map(kDataSize);
190 EXPECT_TRUE(rv);
192 // The mapped memory2 must be at least the size of the original.
193 EXPECT_GE(memory2.mapped_size(), kDataSize);
195 // The mapped memory2 shouldn't exceed rounding for allocation granularity.
196 EXPECT_LT(memory2.mapped_size(),
197 kDataSize2 + base::SysInfo::VMAllocationGranularity());
199 // Verify that opening memory2 didn't truncate or delete memory 1.
200 char *start_ptr = static_cast<char *>(memory2.memory());
201 char *end_ptr = start_ptr + kDataSize;
202 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
203 EXPECT_EQ(*ptr, 'G');
206 memory1.Close();
207 memory2.Close();
209 rv = memory1.Delete(test_name);
210 EXPECT_TRUE(rv);
212 #endif
214 // Check that memory is still mapped after its closed.
215 TEST(SharedMemoryTest, CloseNoUnmap) {
216 const size_t kDataSize = 4096;
218 SharedMemory memory;
219 ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
220 char* ptr = static_cast<char*>(memory.memory());
221 ASSERT_NE(ptr, static_cast<void*>(NULL));
222 memset(ptr, 'G', kDataSize);
224 memory.Close();
226 EXPECT_EQ(ptr, memory.memory());
227 EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
229 for (size_t i = 0; i < kDataSize; i++) {
230 EXPECT_EQ('G', ptr[i]);
233 memory.Unmap();
234 EXPECT_EQ(nullptr, memory.memory());
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
246 // kNumThreads.
248 int threadcounts[] = { 1, kNumThreads };
249 for (size_t i = 0; i < arraysize(threadcounts); i++) {
250 int numthreads = threadcounts[i];
251 scoped_ptr<PlatformThreadHandle[]> thread_handles;
252 scoped_ptr<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 // Allocate private (unique) shared memory with an empty string for a
275 // name. Make sure several of them don't point to the same thing as
276 // we might expect if the names are equal.
277 TEST(SharedMemoryTest, AnonymousPrivate) {
278 int i, j;
279 int count = 4;
280 bool rv;
281 const uint32 kDataSize = 8192;
283 scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]);
284 scoped_ptr<int*[]> pointers(new int*[count]);
285 ASSERT_TRUE(memories.get());
286 ASSERT_TRUE(pointers.get());
288 for (i = 0; i < count; i++) {
289 rv = memories[i].CreateAndMapAnonymous(kDataSize);
290 EXPECT_TRUE(rv);
291 int *ptr = static_cast<int*>(memories[i].memory());
292 EXPECT_TRUE(ptr);
293 pointers[i] = ptr;
296 for (i = 0; i < count; i++) {
297 // zero out the first int in each except for i; for that one, make it 100.
298 for (j = 0; j < count; j++) {
299 if (i == j)
300 pointers[j][0] = 100;
301 else
302 pointers[j][0] = 0;
304 // make sure there is no bleeding of the 100 into the other pointers
305 for (j = 0; j < count; j++) {
306 if (i == j)
307 EXPECT_EQ(100, pointers[j][0]);
308 else
309 EXPECT_EQ(0, pointers[j][0]);
313 for (int i = 0; i < count; i++) {
314 memories[i].Close();
318 TEST(SharedMemoryTest, ShareReadOnly) {
319 StringPiece contents = "Hello World";
321 SharedMemory writable_shmem;
322 SharedMemoryCreateOptions options;
323 options.size = contents.size();
324 options.share_read_only = true;
325 ASSERT_TRUE(writable_shmem.Create(options));
326 ASSERT_TRUE(writable_shmem.Map(options.size));
327 memcpy(writable_shmem.memory(), contents.data(), contents.size());
328 EXPECT_TRUE(writable_shmem.Unmap());
330 SharedMemoryHandle readonly_handle;
331 ASSERT_TRUE(writable_shmem.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
332 &readonly_handle));
333 SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true);
335 ASSERT_TRUE(readonly_shmem.Map(contents.size()));
336 EXPECT_EQ(contents,
337 StringPiece(static_cast<const char*>(readonly_shmem.memory()),
338 contents.size()));
339 EXPECT_TRUE(readonly_shmem.Unmap());
341 // Make sure the writable instance is still writable.
342 ASSERT_TRUE(writable_shmem.Map(contents.size()));
343 StringPiece new_contents = "Goodbye";
344 memcpy(writable_shmem.memory(), new_contents.data(), new_contents.size());
345 EXPECT_EQ(new_contents,
346 StringPiece(static_cast<const char*>(writable_shmem.memory()),
347 new_contents.size()));
349 // We'd like to check that if we send the read-only segment to another
350 // process, then that other process can't reopen it read/write. (Since that
351 // would be a security hole.) Setting up multiple processes is hard in a
352 // unittest, so this test checks that the *current* process can't reopen the
353 // segment read/write. I think the test here is stronger than we actually
354 // care about, but there's a remote possibility that sending a file over a
355 // pipe would transform it into read/write.
356 SharedMemoryHandle handle = readonly_shmem.handle();
358 #if defined(OS_ANDROID)
359 // The "read-only" handle is still writable on Android:
360 // http://crbug.com/320865
361 (void)handle;
362 #elif defined(OS_POSIX)
363 int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle);
364 EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE)
365 << "The descriptor itself should be read-only.";
367 errno = 0;
368 void* writable = mmap(NULL, contents.size(), PROT_READ | PROT_WRITE,
369 MAP_SHARED, handle_fd, 0);
370 int mmap_errno = errno;
371 EXPECT_EQ(MAP_FAILED, writable)
372 << "It shouldn't be possible to re-mmap the descriptor writable.";
373 EXPECT_EQ(EACCES, mmap_errno) << strerror(mmap_errno);
374 if (writable != MAP_FAILED)
375 EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size()));
377 #elif defined(OS_WIN)
378 EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0))
379 << "Shouldn't be able to map memory writable.";
381 HANDLE temp_handle;
382 BOOL rv = ::DuplicateHandle(GetCurrentProcess(),
383 handle,
384 GetCurrentProcess(),
385 &temp_handle,
386 FILE_MAP_ALL_ACCESS,
387 false,
389 EXPECT_EQ(FALSE, rv)
390 << "Shouldn't be able to duplicate the handle into a writable one.";
391 if (rv)
392 base::win::ScopedHandle writable_handle(temp_handle);
393 rv = ::DuplicateHandle(GetCurrentProcess(),
394 handle,
395 GetCurrentProcess(),
396 &temp_handle,
397 FILE_MAP_READ,
398 false,
400 EXPECT_EQ(TRUE, rv)
401 << "Should be able to duplicate the handle into a readable one.";
402 if (rv)
403 base::win::ScopedHandle writable_handle(temp_handle);
404 #else
405 #error Unexpected platform; write a test that tries to make 'handle' writable.
406 #endif // defined(OS_POSIX) || defined(OS_WIN)
409 TEST(SharedMemoryTest, ShareToSelf) {
410 StringPiece contents = "Hello World";
412 SharedMemory shmem;
413 ASSERT_TRUE(shmem.CreateAndMapAnonymous(contents.size()));
414 memcpy(shmem.memory(), contents.data(), contents.size());
415 EXPECT_TRUE(shmem.Unmap());
417 SharedMemoryHandle shared_handle;
418 ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
419 SharedMemory shared(shared_handle, /*readonly=*/false);
421 ASSERT_TRUE(shared.Map(contents.size()));
422 EXPECT_EQ(
423 contents,
424 StringPiece(static_cast<const char*>(shared.memory()), contents.size()));
426 ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
427 SharedMemory readonly(shared_handle, /*readonly=*/true);
429 ASSERT_TRUE(readonly.Map(contents.size()));
430 EXPECT_EQ(contents,
431 StringPiece(static_cast<const char*>(readonly.memory()),
432 contents.size()));
435 TEST(SharedMemoryTest, MapAt) {
436 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
437 const size_t kCount = SysInfo::VMAllocationGranularity();
438 const size_t kDataSize = kCount * sizeof(uint32);
440 SharedMemory memory;
441 ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
442 uint32* ptr = static_cast<uint32*>(memory.memory());
443 ASSERT_NE(ptr, static_cast<void*>(NULL));
445 for (size_t i = 0; i < kCount; ++i) {
446 ptr[i] = i;
449 memory.Unmap();
451 off_t offset = SysInfo::VMAllocationGranularity();
452 ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset));
453 offset /= sizeof(uint32);
454 ptr = static_cast<uint32*>(memory.memory());
455 ASSERT_NE(ptr, static_cast<void*>(NULL));
456 for (size_t i = offset; i < kCount; ++i) {
457 EXPECT_EQ(ptr[i - offset], i);
461 TEST(SharedMemoryTest, MapTwice) {
462 const uint32 kDataSize = 1024;
463 SharedMemory memory;
464 bool rv = memory.CreateAndMapAnonymous(kDataSize);
465 EXPECT_TRUE(rv);
467 void* old_address = memory.memory();
469 rv = memory.Map(kDataSize);
470 EXPECT_FALSE(rv);
471 EXPECT_EQ(old_address, memory.memory());
474 #if defined(OS_POSIX)
475 // This test is not applicable for iOS (crbug.com/399384).
476 #if !defined(OS_IOS)
477 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
478 TEST(SharedMemoryTest, AnonymousExecutable) {
479 const uint32 kTestSize = 1 << 16;
481 SharedMemory shared_memory;
482 SharedMemoryCreateOptions options;
483 options.size = kTestSize;
484 options.executable = true;
486 EXPECT_TRUE(shared_memory.Create(options));
487 EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
489 EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(),
490 PROT_READ | PROT_EXEC));
492 #endif // !defined(OS_IOS)
494 // Android supports a different permission model than POSIX for its "ashmem"
495 // shared memory implementation. So the tests about file permissions are not
496 // included on Android.
497 #if !defined(OS_ANDROID)
499 // Set a umask and restore the old mask on destruction.
500 class ScopedUmaskSetter {
501 public:
502 explicit ScopedUmaskSetter(mode_t target_mask) {
503 old_umask_ = umask(target_mask);
505 ~ScopedUmaskSetter() { umask(old_umask_); }
506 private:
507 mode_t old_umask_;
508 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
511 // Create a shared memory object, check its permissions.
512 TEST(SharedMemoryTest, FilePermissionsAnonymous) {
513 const uint32 kTestSize = 1 << 8;
515 SharedMemory shared_memory;
516 SharedMemoryCreateOptions options;
517 options.size = kTestSize;
518 // Set a file mode creation mask that gives all permissions.
519 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
521 EXPECT_TRUE(shared_memory.Create(options));
523 int shm_fd =
524 SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
525 struct stat shm_stat;
526 EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
527 // Neither the group, nor others should be able to read the shared memory
528 // file.
529 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
530 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
533 // Create a shared memory object, check its permissions.
534 TEST(SharedMemoryTest, FilePermissionsNamed) {
535 const uint32 kTestSize = 1 << 8;
537 SharedMemory shared_memory;
538 SharedMemoryCreateOptions options;
539 options.size = kTestSize;
540 std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) +
541 "-" + Uint64ToString(RandUint64());
542 options.name_deprecated = &shared_mem_name;
543 // Set a file mode creation mask that gives all permissions.
544 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
546 EXPECT_TRUE(shared_memory.Create(options));
547 // Clean-up the backing file name immediately, we don't need it.
548 EXPECT_TRUE(shared_memory.Delete(shared_mem_name));
550 int shm_fd =
551 SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
552 struct stat shm_stat;
553 EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
554 // Neither the group, nor others should have been able to open the shared
555 // memory file while its name existed.
556 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
557 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
559 #endif // !defined(OS_ANDROID)
561 #endif // defined(OS_POSIX)
563 // Map() will return addresses which are aligned to the platform page size, this
564 // varies from platform to platform though. Since we'd like to advertise a
565 // minimum alignment that callers can count on, test for it here.
566 TEST(SharedMemoryTest, MapMinimumAlignment) {
567 static const int kDataSize = 8192;
569 SharedMemory shared_memory;
570 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize));
571 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
572 shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
573 shared_memory.Close();
576 // iOS does not allow multiple processes.
577 // Android ashmem doesn't support named shared memory.
578 #if !defined(OS_IOS) && !defined(OS_ANDROID)
580 // On POSIX it is especially important we test shmem across processes,
581 // not just across threads. But the test is enabled on all platforms.
582 class SharedMemoryProcessTest : public MultiProcessTest {
583 public:
585 static void CleanUp() {
586 SharedMemory memory;
587 memory.Delete(s_test_name_);
590 static int TaskTestMain() {
591 int errors = 0;
592 #if defined(OS_MACOSX)
593 mac::ScopedNSAutoreleasePool pool;
594 #endif
595 SharedMemory memory;
596 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
597 EXPECT_TRUE(rv);
598 if (rv != true)
599 errors++;
600 rv = memory.Map(s_data_size_);
601 EXPECT_TRUE(rv);
602 if (rv != true)
603 errors++;
604 int *ptr = static_cast<int*>(memory.memory());
606 // This runs concurrently in multiple processes. Writes need to be atomic.
607 base::subtle::Barrier_AtomicIncrement(ptr, 1);
608 memory.Close();
609 return errors;
612 static const char* const s_test_name_;
613 static const uint32 s_data_size_;
616 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
617 const uint32 SharedMemoryProcessTest::s_data_size_ = 1024;
619 TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) {
620 SharedMemoryProcessTest::CleanUp();
622 // Create a shared memory region. Set the first word to 0.
623 SharedMemory memory;
624 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
625 ASSERT_TRUE(rv);
626 rv = memory.Map(s_data_size_);
627 ASSERT_TRUE(rv);
628 int* ptr = static_cast<int*>(memory.memory());
629 *ptr = 0;
631 // Start |kNumTasks| processes, each of which atomically increments the first
632 // word by 1.
633 Process processes[kNumTasks];
634 for (int index = 0; index < kNumTasks; ++index) {
635 processes[index] = SpawnChild("SharedMemoryTestMain");
636 ASSERT_TRUE(processes[index].IsValid());
639 // Check that each process exited correctly.
640 int exit_code = 0;
641 for (int index = 0; index < kNumTasks; ++index) {
642 EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
643 EXPECT_EQ(0, exit_code);
646 // Check that the shared memory region reflects |kNumTasks| increments.
647 ASSERT_EQ(kNumTasks, *ptr);
649 memory.Close();
650 SharedMemoryProcessTest::CleanUp();
653 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
654 return SharedMemoryProcessTest::TaskTestMain();
657 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
659 } // namespace base