evan@chromium.org | 3c0bc35 | 2012-02-14 09:29:14 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 4 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 5 | #include "base/basictypes.h" |
ensonic@google.com | 23b1cc0 | 2011-12-07 00:09:56 +0900 | [diff] [blame] | 6 | #if defined(OS_MACOSX) |
| 7 | #include "base/mac/scoped_nsautorelease_pool.h" |
| 8 | #endif |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 9 | #include "base/memory/scoped_ptr.h" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 10 | #include "base/shared_memory.h" |
brettw@chromium.org | 1c8c3be | 2010-08-18 04:40:11 +0900 | [diff] [blame] | 11 | #include "base/test/multiprocess_test.h" |
brettw@chromium.org | 6139182 | 2011-01-01 05:02:16 +0900 | [diff] [blame] | 12 | #include "base/threading/platform_thread.h" |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 13 | #include "base/time.h" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 14 | #include "testing/gtest/include/gtest/gtest.h" |
brettw@chromium.org | 1c8c3be | 2010-08-18 04:40:11 +0900 | [diff] [blame] | 15 | #include "testing/multiprocess_func_list.h" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 16 | |
jam@chromium.org | 9730fbd | 2011-10-29 12:44:44 +0900 | [diff] [blame] | 17 | #if defined(OS_MACOSX) |
| 18 | #include "base/mac/scoped_nsautorelease_pool.h" |
| 19 | #endif |
| 20 | |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 21 | #if defined(OS_POSIX) |
| 22 | #include <sys/mman.h> |
| 23 | #endif |
| 24 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 25 | static const int kNumThreads = 5; |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 26 | static const int kNumTasks = 5; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 27 | |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 28 | namespace base { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 29 | |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 30 | namespace { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 31 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 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 { |
| 36 | public: |
| 37 | explicit MultipleThreadMain(int16 id) : id_(id) {} |
| 38 | ~MultipleThreadMain() {} |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 39 | |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 40 | static void CleanUp() { |
| 41 | SharedMemory memory; |
maruel@chromium.org | 8fe7adc | 2009-03-04 00:01:12 +0900 | [diff] [blame] | 42 | memory.Delete(s_test_name_); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 43 | } |
| 44 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 45 | // PlatformThread::Delegate interface. |
| 46 | void ThreadMain() { |
jam@chromium.org | 9730fbd | 2011-10-29 12:44:44 +0900 | [diff] [blame] | 47 | #if defined(OS_MACOSX) |
| 48 | mac::ScopedNSAutoreleasePool pool; |
| 49 | #endif |
jam@chromium.org | e74ca94 | 2010-02-17 08:58:27 +0900 | [diff] [blame] | 50 | const uint32 kDataSize = 1024; |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 51 | SharedMemory memory; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 52 | bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 53 | EXPECT_TRUE(rv); |
| 54 | rv = memory.Map(kDataSize); |
| 55 | EXPECT_TRUE(rv); |
| 56 | int *ptr = static_cast<int*>(memory.memory()) + id_; |
thakis@chromium.org | f75ccb4 | 2011-10-14 16:28:03 +0900 | [diff] [blame] | 57 | EXPECT_EQ(0, *ptr); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 58 | |
| 59 | for (int idx = 0; idx < 100; idx++) { |
| 60 | *ptr = idx; |
tedvessenes@gmail.com | aaa6303 | 2012-01-01 07:53:51 +0900 | [diff] [blame] | 61 | PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 62 | EXPECT_EQ(*ptr, idx); |
| 63 | } |
thakis@chromium.org | f75ccb4 | 2011-10-14 16:28:03 +0900 | [diff] [blame] | 64 | // Reset back to 0 for the next test that uses the same name. |
| 65 | *ptr = 0; |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 66 | |
| 67 | memory.Close(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 68 | } |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 69 | |
| 70 | private: |
| 71 | int16 id_; |
| 72 | |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 73 | static const char* const s_test_name_; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 74 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 75 | DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); |
| 76 | }; |
| 77 | |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 78 | const char* const MultipleThreadMain::s_test_name_ = |
| 79 | "SharedMemoryOpenThreadTest"; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 80 | |
| 81 | // TODO(port): |
| 82 | // This test requires the ability to pass file descriptors between processes. |
| 83 | // We haven't done that yet in Chrome for POSIX. |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 84 | #if defined(OS_WIN) |
| 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 |
| 88 | // correct. |
| 89 | class MultipleLockThread : public PlatformThread::Delegate { |
| 90 | public: |
| 91 | explicit MultipleLockThread(int id) : id_(id) {} |
| 92 | ~MultipleLockThread() {} |
| 93 | |
| 94 | // PlatformThread::Delegate interface. |
| 95 | void ThreadMain() { |
jam@chromium.org | e74ca94 | 2010-02-17 08:58:27 +0900 | [diff] [blame] | 96 | const uint32 kDataSize = sizeof(int); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 97 | SharedMemoryHandle handle = NULL; |
| 98 | { |
| 99 | SharedMemory memory1; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 100 | EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest", |
| 101 | true, kDataSize)); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 102 | EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); |
| 103 | // TODO(paulg): Implement this once we have a posix version of |
| 104 | // SharedMemory::ShareToProcess. |
| 105 | EXPECT_TRUE(true); |
| 106 | } |
| 107 | |
| 108 | SharedMemory memory2(handle, false); |
| 109 | EXPECT_TRUE(memory2.Map(kDataSize)); |
| 110 | volatile int* const ptr = static_cast<int*>(memory2.memory()); |
| 111 | |
| 112 | for (int idx = 0; idx < 20; idx++) { |
| 113 | memory2.Lock(); |
| 114 | int i = (id_ << 16) + idx; |
| 115 | *ptr = i; |
tedvessenes@gmail.com | aaa6303 | 2012-01-01 07:53:51 +0900 | [diff] [blame] | 116 | PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 117 | EXPECT_EQ(*ptr, i); |
| 118 | memory2.Unlock(); |
| 119 | } |
| 120 | |
| 121 | memory2.Close(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 122 | } |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 123 | |
| 124 | private: |
| 125 | int id_; |
| 126 | |
| 127 | DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); |
| 128 | }; |
| 129 | #endif |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 130 | |
| 131 | } // namespace |
| 132 | |
| 133 | TEST(SharedMemoryTest, OpenClose) { |
jam@chromium.org | e74ca94 | 2010-02-17 08:58:27 +0900 | [diff] [blame] | 134 | const uint32 kDataSize = 1024; |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 135 | std::string test_name = "SharedMemoryOpenCloseTest"; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 136 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 137 | // Open two handles to a memory segment, confirm that they are mapped |
| 138 | // separately yet point to the same space. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 139 | SharedMemory memory1; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 140 | bool rv = memory1.Delete(test_name); |
| 141 | EXPECT_TRUE(rv); |
| 142 | rv = memory1.Delete(test_name); |
| 143 | EXPECT_TRUE(rv); |
| 144 | rv = memory1.Open(test_name, false); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 145 | EXPECT_FALSE(rv); |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 146 | rv = memory1.CreateNamed(test_name, false, kDataSize); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 147 | EXPECT_TRUE(rv); |
| 148 | rv = memory1.Map(kDataSize); |
| 149 | EXPECT_TRUE(rv); |
| 150 | SharedMemory memory2; |
| 151 | rv = memory2.Open(test_name, false); |
| 152 | EXPECT_TRUE(rv); |
| 153 | rv = memory2.Map(kDataSize); |
| 154 | EXPECT_TRUE(rv); |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 155 | EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 156 | |
maruel@google.com | 76cff08 | 2008-09-13 02:41:52 +0900 | [diff] [blame] | 157 | // Make sure we don't segfault. (it actually happened!) |
| 158 | ASSERT_NE(memory1.memory(), static_cast<void*>(NULL)); |
| 159 | ASSERT_NE(memory2.memory(), static_cast<void*>(NULL)); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 160 | |
| 161 | // Write data to the first memory segment, verify contents of second. |
| 162 | memset(memory1.memory(), '1', kDataSize); |
| 163 | EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); |
| 164 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 165 | // Close the first memory segment, and verify the second has the right data. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 166 | memory1.Close(); |
| 167 | char *start_ptr = static_cast<char *>(memory2.memory()); |
| 168 | char *end_ptr = start_ptr + kDataSize; |
| 169 | for (char* ptr = start_ptr; ptr < end_ptr; ptr++) |
| 170 | EXPECT_EQ(*ptr, '1'); |
| 171 | |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 172 | // Close the second memory segment. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 173 | memory2.Close(); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 174 | |
| 175 | rv = memory1.Delete(test_name); |
| 176 | EXPECT_TRUE(rv); |
| 177 | rv = memory2.Delete(test_name); |
| 178 | EXPECT_TRUE(rv); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 179 | } |
| 180 | |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 181 | TEST(SharedMemoryTest, OpenExclusive) { |
| 182 | const uint32 kDataSize = 1024; |
| 183 | const uint32 kDataSize2 = 2048; |
| 184 | std::ostringstream test_name_stream; |
| 185 | test_name_stream << "SharedMemoryOpenExclusiveTest." |
| 186 | << Time::Now().ToDoubleT(); |
| 187 | std::string test_name = test_name_stream.str(); |
| 188 | |
| 189 | // Open two handles to a memory segment and check that open_existing works |
| 190 | // as expected. |
| 191 | SharedMemory memory1; |
| 192 | bool rv = memory1.CreateNamed(test_name, false, kDataSize); |
| 193 | EXPECT_TRUE(rv); |
| 194 | |
| 195 | // Memory1 knows it's size because it created it. |
| 196 | EXPECT_EQ(memory1.created_size(), kDataSize); |
| 197 | |
| 198 | rv = memory1.Map(kDataSize); |
| 199 | EXPECT_TRUE(rv); |
| 200 | |
| 201 | memset(memory1.memory(), 'G', kDataSize); |
| 202 | |
| 203 | SharedMemory memory2; |
| 204 | // Should not be able to create if openExisting is false. |
| 205 | rv = memory2.CreateNamed(test_name, false, kDataSize2); |
| 206 | EXPECT_FALSE(rv); |
| 207 | |
| 208 | // Should be able to create with openExisting true. |
| 209 | rv = memory2.CreateNamed(test_name, true, kDataSize2); |
| 210 | EXPECT_TRUE(rv); |
| 211 | |
| 212 | // Memory2 shouldn't know the size because we didn't create it. |
| 213 | EXPECT_EQ(memory2.created_size(), 0U); |
| 214 | |
| 215 | // We should be able to map the original size. |
| 216 | rv = memory2.Map(kDataSize); |
| 217 | EXPECT_TRUE(rv); |
| 218 | |
| 219 | // Verify that opening memory2 didn't truncate or delete memory 1. |
| 220 | char *start_ptr = static_cast<char *>(memory2.memory()); |
| 221 | char *end_ptr = start_ptr + kDataSize; |
| 222 | for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { |
| 223 | EXPECT_EQ(*ptr, 'G'); |
| 224 | } |
| 225 | |
| 226 | memory1.Close(); |
| 227 | memory2.Close(); |
| 228 | |
| 229 | rv = memory1.Delete(test_name); |
| 230 | EXPECT_TRUE(rv); |
| 231 | } |
| 232 | |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 233 | // Create a set of N threads to each open a shared memory segment and write to |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 234 | // it. Verify that they are always reading/writing consistent data. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 235 | TEST(SharedMemoryTest, MultipleThreads) { |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 236 | MultipleThreadMain::CleanUp(); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 237 | // On POSIX we have a problem when 2 threads try to create the shmem |
| 238 | // (a file) at exactly the same time, since create both creates the |
| 239 | // file and zerofills it. We solve the problem for this unit test |
| 240 | // (make it not flaky) by starting with 1 thread, then |
| 241 | // intentionally don't clean up its shmem before running with |
| 242 | // kNumThreads. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 243 | |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 244 | int threadcounts[] = { 1, kNumThreads }; |
thakis@chromium.org | f75ccb4 | 2011-10-14 16:28:03 +0900 | [diff] [blame] | 245 | for (size_t i = 0; i < arraysize(threadcounts); i++) { |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 246 | int numthreads = threadcounts[i]; |
| 247 | scoped_array<PlatformThreadHandle> thread_handles; |
| 248 | scoped_array<MultipleThreadMain*> thread_delegates; |
| 249 | |
| 250 | thread_handles.reset(new PlatformThreadHandle[numthreads]); |
| 251 | thread_delegates.reset(new MultipleThreadMain*[numthreads]); |
| 252 | |
| 253 | // Spawn the threads. |
| 254 | for (int16 index = 0; index < numthreads; index++) { |
| 255 | PlatformThreadHandle pth; |
| 256 | thread_delegates[index] = new MultipleThreadMain(index); |
| 257 | EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); |
| 258 | thread_handles[index] = pth; |
| 259 | } |
| 260 | |
| 261 | // Wait for the threads to finish. |
| 262 | for (int index = 0; index < numthreads; index++) { |
| 263 | PlatformThread::Join(thread_handles[index]); |
| 264 | delete thread_delegates[index]; |
| 265 | } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 266 | } |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 267 | MultipleThreadMain::CleanUp(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 268 | } |
| 269 | |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 270 | // TODO(port): this test requires the MultipleLockThread class |
| 271 | // (defined above), which requires the ability to pass file |
| 272 | // descriptors between processes. We haven't done that yet in Chrome |
| 273 | // for POSIX. |
| 274 | #if defined(OS_WIN) |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 275 | // Create a set of threads to each open a shared memory segment and write to it |
| 276 | // with the lock held. Verify that they are always reading/writing consistent |
| 277 | // data. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 278 | TEST(SharedMemoryTest, Lock) { |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 279 | PlatformThreadHandle thread_handles[kNumThreads]; |
| 280 | MultipleLockThread* thread_delegates[kNumThreads]; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 281 | |
| 282 | // Spawn the threads. |
| 283 | for (int index = 0; index < kNumThreads; ++index) { |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 284 | PlatformThreadHandle pth; |
| 285 | thread_delegates[index] = new MultipleLockThread(index); |
| 286 | EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); |
| 287 | thread_handles[index] = pth; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | // Wait for the threads to finish. |
| 291 | for (int index = 0; index < kNumThreads; ++index) { |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 292 | PlatformThread::Join(thread_handles[index]); |
| 293 | delete thread_delegates[index]; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 294 | } |
| 295 | } |
paulg@google.com | 78da663 | 2008-09-11 09:31:43 +0900 | [diff] [blame] | 296 | #endif |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 297 | |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 298 | // Allocate private (unique) shared memory with an empty string for a |
| 299 | // name. Make sure several of them don't point to the same thing as |
| 300 | // we might expect if the names are equal. |
| 301 | TEST(SharedMemoryTest, AnonymousPrivate) { |
| 302 | int i, j; |
| 303 | int count = 4; |
| 304 | bool rv; |
jam@chromium.org | e74ca94 | 2010-02-17 08:58:27 +0900 | [diff] [blame] | 305 | const uint32 kDataSize = 8192; |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 306 | |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 307 | scoped_array<SharedMemory> memories(new SharedMemory[count]); |
| 308 | scoped_array<int*> pointers(new int*[count]); |
| 309 | ASSERT_TRUE(memories.get()); |
| 310 | ASSERT_TRUE(pointers.get()); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 311 | |
| 312 | for (i = 0; i < count; i++) { |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 313 | rv = memories[i].CreateAndMapAnonymous(kDataSize); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 314 | EXPECT_TRUE(rv); |
| 315 | int *ptr = static_cast<int*>(memories[i].memory()); |
| 316 | EXPECT_TRUE(ptr); |
| 317 | pointers[i] = ptr; |
| 318 | } |
| 319 | |
| 320 | for (i = 0; i < count; i++) { |
| 321 | // zero out the first int in each except for i; for that one, make it 100. |
| 322 | for (j = 0; j < count; j++) { |
| 323 | if (i == j) |
| 324 | pointers[j][0] = 100; |
| 325 | else |
| 326 | pointers[j][0] = 0; |
| 327 | } |
| 328 | // make sure there is no bleeding of the 100 into the other pointers |
| 329 | for (j = 0; j < count; j++) { |
| 330 | if (i == j) |
| 331 | EXPECT_EQ(100, pointers[j][0]); |
| 332 | else |
| 333 | EXPECT_EQ(0, pointers[j][0]); |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | for (int i = 0; i < count; i++) { |
| 338 | memories[i].Close(); |
| 339 | } |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 340 | } |
| 341 | |
mcgrathr@chromium.org | 45910f7 | 2011-12-02 08:19:31 +0900 | [diff] [blame] | 342 | #if defined(OS_POSIX) |
| 343 | // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. |
| 344 | TEST(SharedMemoryTest, AnonymousExecutable) { |
| 345 | const uint32 kTestSize = 1 << 16; |
| 346 | |
| 347 | SharedMemory shared_memory; |
| 348 | SharedMemoryCreateOptions options; |
| 349 | options.size = kTestSize; |
| 350 | options.executable = true; |
| 351 | |
| 352 | EXPECT_TRUE(shared_memory.Create(options)); |
| 353 | EXPECT_TRUE(shared_memory.Map(shared_memory.created_size())); |
| 354 | |
| 355 | EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.created_size(), |
| 356 | PROT_READ | PROT_EXEC)); |
| 357 | } |
| 358 | #endif |
| 359 | |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 360 | // On POSIX it is especially important we test shmem across processes, |
| 361 | // not just across threads. But the test is enabled on all platforms. |
brettw@chromium.org | 6139182 | 2011-01-01 05:02:16 +0900 | [diff] [blame] | 362 | class SharedMemoryProcessTest : public MultiProcessTest { |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 363 | public: |
| 364 | |
| 365 | static void CleanUp() { |
| 366 | SharedMemory memory; |
maruel@chromium.org | 8fe7adc | 2009-03-04 00:01:12 +0900 | [diff] [blame] | 367 | memory.Delete(s_test_name_); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 368 | } |
| 369 | |
| 370 | static int TaskTestMain() { |
| 371 | int errors = 0; |
jam@chromium.org | 9730fbd | 2011-10-29 12:44:44 +0900 | [diff] [blame] | 372 | #if defined(OS_MACOSX) |
| 373 | mac::ScopedNSAutoreleasePool pool; |
| 374 | #endif |
jam@chromium.org | e74ca94 | 2010-02-17 08:58:27 +0900 | [diff] [blame] | 375 | const uint32 kDataSize = 1024; |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 376 | SharedMemory memory; |
dmaclach@chromium.org | bb6b763 | 2010-10-28 03:16:06 +0900 | [diff] [blame] | 377 | bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 378 | EXPECT_TRUE(rv); |
| 379 | if (rv != true) |
| 380 | errors++; |
| 381 | rv = memory.Map(kDataSize); |
| 382 | EXPECT_TRUE(rv); |
| 383 | if (rv != true) |
| 384 | errors++; |
| 385 | int *ptr = static_cast<int*>(memory.memory()); |
| 386 | |
| 387 | for (int idx = 0; idx < 20; idx++) { |
| 388 | memory.Lock(); |
| 389 | int i = (1 << 16) + idx; |
| 390 | *ptr = i; |
tedvessenes@gmail.com | aaa6303 | 2012-01-01 07:53:51 +0900 | [diff] [blame] | 391 | PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 392 | if (*ptr != i) |
| 393 | errors++; |
| 394 | memory.Unlock(); |
| 395 | } |
| 396 | |
| 397 | memory.Close(); |
| 398 | return errors; |
| 399 | } |
| 400 | |
| 401 | private: |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 402 | static const char* const s_test_name_; |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 403 | }; |
| 404 | |
evan@chromium.org | 5675699 | 2010-09-30 05:32:22 +0900 | [diff] [blame] | 405 | const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 406 | |
evan@chromium.org | 3c0bc35 | 2012-02-14 09:29:14 +0900 | [diff] [blame] | 407 | // http://crbug.com/61589 |
bauerb@chromium.org | e5caa27 | 2010-11-03 00:55:45 +0900 | [diff] [blame] | 408 | #if defined(OS_MACOSX) |
evan@chromium.org | 3c0bc35 | 2012-02-14 09:29:14 +0900 | [diff] [blame] | 409 | #define MAYBE_Tasks DISABLED_Tasks |
bauerb@chromium.org | e5caa27 | 2010-11-03 00:55:45 +0900 | [diff] [blame] | 410 | #else |
| 411 | #define MAYBE_Tasks Tasks |
| 412 | #endif |
| 413 | |
| 414 | TEST_F(SharedMemoryProcessTest, MAYBE_Tasks) { |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 415 | SharedMemoryProcessTest::CleanUp(); |
| 416 | |
brettw@chromium.org | 6139182 | 2011-01-01 05:02:16 +0900 | [diff] [blame] | 417 | ProcessHandle handles[kNumTasks]; |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 418 | for (int index = 0; index < kNumTasks; ++index) { |
brettw@chromium.org | 1c8c3be | 2010-08-18 04:40:11 +0900 | [diff] [blame] | 419 | handles[index] = SpawnChild("SharedMemoryTestMain", false); |
rsleevi@chromium.org | 014b1f9 | 2011-07-03 07:01:14 +0900 | [diff] [blame] | 420 | ASSERT_TRUE(handles[index]); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 421 | } |
| 422 | |
| 423 | int exit_code = 0; |
| 424 | for (int index = 0; index < kNumTasks; ++index) { |
brettw@chromium.org | 6139182 | 2011-01-01 05:02:16 +0900 | [diff] [blame] | 425 | EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code)); |
tbreisacher@chromium.org | 4474fb1 | 2012-03-17 07:09:29 +0900 | [diff] [blame] | 426 | EXPECT_EQ(0, exit_code); |
jrg@chromium.org | 81e2260 | 2009-02-06 04:04:34 +0900 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | SharedMemoryProcessTest::CleanUp(); |
| 430 | } |
| 431 | |
| 432 | MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { |
| 433 | return SharedMemoryProcessTest::TaskTestMain(); |
jrg@chromium.org | d505c3a | 2009-02-04 09:58:39 +0900 | [diff] [blame] | 434 | } |
| 435 | |
brettw@google.com | c60d989 | 2008-11-14 12:25:15 +0900 | [diff] [blame] | 436 | } // namespace base |