Home | History | Annotate | Download | only in base
      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.
      4 
      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"
     14 
     15 static const int kNumThreads = 5;
     16 static const int kNumTasks = 5;
     17 
     18 namespace base {
     19 
     20 namespace {
     21 
     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 {
     26  public:
     27   explicit MultipleThreadMain(int16 id) : id_(id) {}
     28   ~MultipleThreadMain() {}
     29 
     30   static void CleanUp() {
     31     SharedMemory memory;
     32     memory.Delete(s_test_name_);
     33   }
     34 
     35   // PlatformThread::Delegate interface.
     36   void ThreadMain() {
     37     mac::ScopedNSAutoreleasePool pool;  // noop if not OSX
     38     const uint32 kDataSize = 1024;
     39     SharedMemory memory;
     40     bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
     41     EXPECT_TRUE(rv);
     42     rv = memory.Map(kDataSize);
     43     EXPECT_TRUE(rv);
     44     int *ptr = static_cast<int*>(memory.memory()) + id_;
     45     EXPECT_EQ(*ptr, 0);
     46 
     47     for (int idx = 0; idx < 100; idx++) {
     48       *ptr = idx;
     49       PlatformThread::Sleep(1);  // Short wait.
     50       EXPECT_EQ(*ptr, idx);
     51     }
     52 
     53     memory.Close();
     54   }
     55 
     56  private:
     57   int16 id_;
     58 
     59   static const char* const s_test_name_;
     60 
     61   DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
     62 };
     63 
     64 const char* const MultipleThreadMain::s_test_name_ =
     65     "SharedMemoryOpenThreadTest";
     66 
     67 // TODO(port):
     68 // This test requires the ability to pass file descriptors between processes.
     69 // We haven't done that yet in Chrome for POSIX.
     70 #if defined(OS_WIN)
     71 // Each thread will open the shared memory.  Each thread will take the memory,
     72 // and keep changing it while trying to lock it, with some small pauses in
     73 // between. Verify that each thread's value in the shared memory is always
     74 // correct.
     75 class MultipleLockThread : public PlatformThread::Delegate {
     76  public:
     77   explicit MultipleLockThread(int id) : id_(id) {}
     78   ~MultipleLockThread() {}
     79 
     80   // PlatformThread::Delegate interface.
     81   void ThreadMain() {
     82     const uint32 kDataSize = sizeof(int);
     83     SharedMemoryHandle handle = NULL;
     84     {
     85       SharedMemory memory1;
     86       EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest",
     87                                  true, kDataSize));
     88       EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
     89       // TODO(paulg): Implement this once we have a posix version of
     90       // SharedMemory::ShareToProcess.
     91       EXPECT_TRUE(true);
     92     }
     93 
     94     SharedMemory memory2(handle, false);
     95     EXPECT_TRUE(memory2.Map(kDataSize));
     96     volatile int* const ptr = static_cast<int*>(memory2.memory());
     97 
     98     for (int idx = 0; idx < 20; idx++) {
     99       memory2.Lock();
    100       int i = (id_ << 16) + idx;
    101       *ptr = i;
    102       PlatformThread::Sleep(1);  // Short wait.
    103       EXPECT_EQ(*ptr, i);
    104       memory2.Unlock();
    105     }
    106 
    107     memory2.Close();
    108   }
    109 
    110  private:
    111   int id_;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
    114 };
    115 #endif
    116 
    117 }  // namespace
    118 
    119 TEST(SharedMemoryTest, OpenClose) {
    120   const uint32 kDataSize = 1024;
    121   std::string test_name = "SharedMemoryOpenCloseTest";
    122 
    123   // Open two handles to a memory segment, confirm that they are mapped
    124   // separately yet point to the same space.
    125   SharedMemory memory1;
    126   bool rv = memory1.Delete(test_name);
    127   EXPECT_TRUE(rv);
    128   rv = memory1.Delete(test_name);
    129   EXPECT_TRUE(rv);
    130   rv = memory1.Open(test_name, false);
    131   EXPECT_FALSE(rv);
    132   rv = memory1.CreateNamed(test_name, false, kDataSize);
    133   EXPECT_TRUE(rv);
    134   rv = memory1.Map(kDataSize);
    135   EXPECT_TRUE(rv);
    136   SharedMemory memory2;
    137   rv = memory2.Open(test_name, false);
    138   EXPECT_TRUE(rv);
    139   rv = memory2.Map(kDataSize);
    140   EXPECT_TRUE(rv);
    141   EXPECT_NE(memory1.memory(), memory2.memory());  // Compare the pointers.
    142 
    143   // Make sure we don't segfault. (it actually happened!)
    144   ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
    145   ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
    146 
    147   // Write data to the first memory segment, verify contents of second.
    148   memset(memory1.memory(), '1', kDataSize);
    149   EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
    150 
    151   // Close the first memory segment, and verify the second has the right data.
    152   memory1.Close();
    153   char *start_ptr = static_cast<char *>(memory2.memory());
    154   char *end_ptr = start_ptr + kDataSize;
    155   for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
    156     EXPECT_EQ(*ptr, '1');
    157 
    158   // Close the second memory segment.
    159   memory2.Close();
    160 
    161   rv = memory1.Delete(test_name);
    162   EXPECT_TRUE(rv);
    163   rv = memory2.Delete(test_name);
    164   EXPECT_TRUE(rv);
    165 }
    166 
    167 TEST(SharedMemoryTest, OpenExclusive) {
    168   const uint32 kDataSize = 1024;
    169   const uint32 kDataSize2 = 2048;
    170   std::ostringstream test_name_stream;
    171   test_name_stream << "SharedMemoryOpenExclusiveTest."
    172                    << Time::Now().ToDoubleT();
    173   std::string test_name = test_name_stream.str();
    174 
    175   // Open two handles to a memory segment and check that open_existing works
    176   // as expected.
    177   SharedMemory memory1;
    178   bool rv = memory1.CreateNamed(test_name, false, kDataSize);
    179   EXPECT_TRUE(rv);
    180 
    181   // Memory1 knows it's size because it created it.
    182   EXPECT_EQ(memory1.created_size(), kDataSize);
    183 
    184   rv = memory1.Map(kDataSize);
    185   EXPECT_TRUE(rv);
    186 
    187   memset(memory1.memory(), 'G', kDataSize);
    188 
    189   SharedMemory memory2;
    190   // Should not be able to create if openExisting is false.
    191   rv = memory2.CreateNamed(test_name, false, kDataSize2);
    192   EXPECT_FALSE(rv);
    193 
    194   // Should be able to create with openExisting true.
    195   rv = memory2.CreateNamed(test_name, true, kDataSize2);
    196   EXPECT_TRUE(rv);
    197 
    198   // Memory2 shouldn't know the size because we didn't create it.
    199   EXPECT_EQ(memory2.created_size(), 0U);
    200 
    201   // We should be able to map the original size.
    202   rv = memory2.Map(kDataSize);
    203   EXPECT_TRUE(rv);
    204 
    205   // Verify that opening memory2 didn't truncate or delete memory 1.
    206   char *start_ptr = static_cast<char *>(memory2.memory());
    207   char *end_ptr = start_ptr + kDataSize;
    208   for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
    209     EXPECT_EQ(*ptr, 'G');
    210   }
    211 
    212   memory1.Close();
    213   memory2.Close();
    214 
    215   rv = memory1.Delete(test_name);
    216   EXPECT_TRUE(rv);
    217 }
    218 
    219 // Create a set of N threads to each open a shared memory segment and write to
    220 // it. Verify that they are always reading/writing consistent data.
    221 TEST(SharedMemoryTest, MultipleThreads) {
    222   MultipleThreadMain::CleanUp();
    223   // On POSIX we have a problem when 2 threads try to create the shmem
    224   // (a file) at exactly the same time, since create both creates the
    225   // file and zerofills it.  We solve the problem for this unit test
    226   // (make it not flaky) by starting with 1 thread, then
    227   // intentionally don't clean up its shmem before running with
    228   // kNumThreads.
    229 
    230   int threadcounts[] = { 1, kNumThreads };
    231   for (size_t i = 0; i < sizeof(threadcounts) / sizeof(threadcounts); i++) {
    232     int numthreads = threadcounts[i];
    233     scoped_array<PlatformThreadHandle> thread_handles;
    234     scoped_array<MultipleThreadMain*> thread_delegates;
    235 
    236     thread_handles.reset(new PlatformThreadHandle[numthreads]);
    237     thread_delegates.reset(new MultipleThreadMain*[numthreads]);
    238 
    239     // Spawn the threads.
    240     for (int16 index = 0; index < numthreads; index++) {
    241       PlatformThreadHandle pth;
    242       thread_delegates[index] = new MultipleThreadMain(index);
    243       EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
    244       thread_handles[index] = pth;
    245     }
    246 
    247     // Wait for the threads to finish.
    248     for (int index = 0; index < numthreads; index++) {
    249       PlatformThread::Join(thread_handles[index]);
    250       delete thread_delegates[index];
    251     }
    252   }
    253   MultipleThreadMain::CleanUp();
    254 }
    255 
    256 // TODO(port): this test requires the MultipleLockThread class
    257 // (defined above), which requires the ability to pass file
    258 // descriptors between processes.  We haven't done that yet in Chrome
    259 // for POSIX.
    260 #if defined(OS_WIN)
    261 // Create a set of threads to each open a shared memory segment and write to it
    262 // with the lock held. Verify that they are always reading/writing consistent
    263 // data.
    264 TEST(SharedMemoryTest, Lock) {
    265   PlatformThreadHandle thread_handles[kNumThreads];
    266   MultipleLockThread* thread_delegates[kNumThreads];
    267 
    268   // Spawn the threads.
    269   for (int index = 0; index < kNumThreads; ++index) {
    270     PlatformThreadHandle pth;
    271     thread_delegates[index] = new MultipleLockThread(index);
    272     EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
    273     thread_handles[index] = pth;
    274   }
    275 
    276   // Wait for the threads to finish.
    277   for (int index = 0; index < kNumThreads; ++index) {
    278     PlatformThread::Join(thread_handles[index]);
    279     delete thread_delegates[index];
    280   }
    281 }
    282 #endif
    283 
    284 // Allocate private (unique) shared memory with an empty string for a
    285 // name.  Make sure several of them don't point to the same thing as
    286 // we might expect if the names are equal.
    287 TEST(SharedMemoryTest, AnonymousPrivate) {
    288   int i, j;
    289   int count = 4;
    290   bool rv;
    291   const uint32 kDataSize = 8192;
    292 
    293   scoped_array<SharedMemory> memories(new SharedMemory[count]);
    294   scoped_array<int*> pointers(new int*[count]);
    295   ASSERT_TRUE(memories.get());
    296   ASSERT_TRUE(pointers.get());
    297 
    298   for (i = 0; i < count; i++) {
    299     rv = memories[i].CreateAndMapAnonymous(kDataSize);
    300     EXPECT_TRUE(rv);
    301     int *ptr = static_cast<int*>(memories[i].memory());
    302     EXPECT_TRUE(ptr);
    303     pointers[i] = ptr;
    304   }
    305 
    306   for (i = 0; i < count; i++) {
    307     // zero out the first int in each except for i; for that one, make it 100.
    308     for (j = 0; j < count; j++) {
    309       if (i == j)
    310         pointers[j][0] = 100;
    311       else
    312         pointers[j][0] = 0;
    313     }
    314     // make sure there is no bleeding of the 100 into the other pointers
    315     for (j = 0; j < count; j++) {
    316       if (i == j)
    317         EXPECT_EQ(100, pointers[j][0]);
    318       else
    319         EXPECT_EQ(0, pointers[j][0]);
    320     }
    321   }
    322 
    323   for (int i = 0; i < count; i++) {
    324     memories[i].Close();
    325   }
    326 }
    327 
    328 // On POSIX it is especially important we test shmem across processes,
    329 // not just across threads.  But the test is enabled on all platforms.
    330 class SharedMemoryProcessTest : public MultiProcessTest {
    331  public:
    332 
    333   static void CleanUp() {
    334     SharedMemory memory;
    335     memory.Delete(s_test_name_);
    336   }
    337 
    338   static int TaskTestMain() {
    339     int errors = 0;
    340     mac::ScopedNSAutoreleasePool pool;  // noop if not OSX
    341     const uint32 kDataSize = 1024;
    342     SharedMemory memory;
    343     bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
    344     EXPECT_TRUE(rv);
    345     if (rv != true)
    346       errors++;
    347     rv = memory.Map(kDataSize);
    348     EXPECT_TRUE(rv);
    349     if (rv != true)
    350       errors++;
    351     int *ptr = static_cast<int*>(memory.memory());
    352 
    353     for (int idx = 0; idx < 20; idx++) {
    354       memory.Lock();
    355       int i = (1 << 16) + idx;
    356       *ptr = i;
    357       PlatformThread::Sleep(10);  // Short wait.
    358       if (*ptr != i)
    359         errors++;
    360       memory.Unlock();
    361     }
    362 
    363     memory.Close();
    364     return errors;
    365   }
    366 
    367  private:
    368   static const char* const s_test_name_;
    369 };
    370 
    371 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
    372 
    373 
    374 #if defined(OS_MACOSX)
    375 #define MAYBE_Tasks FLAKY_Tasks
    376 #else
    377 #define MAYBE_Tasks Tasks
    378 #endif
    379 
    380 TEST_F(SharedMemoryProcessTest, MAYBE_Tasks) {
    381   SharedMemoryProcessTest::CleanUp();
    382 
    383   ProcessHandle handles[kNumTasks];
    384   for (int index = 0; index < kNumTasks; ++index) {
    385     handles[index] = SpawnChild("SharedMemoryTestMain", false);
    386   }
    387 
    388   int exit_code = 0;
    389   for (int index = 0; index < kNumTasks; ++index) {
    390     EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code));
    391     EXPECT_TRUE(exit_code == 0);
    392   }
    393 
    394   SharedMemoryProcessTest::CleanUp();
    395 }
    396 
    397 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
    398   return SharedMemoryProcessTest::TaskTestMain();
    399 }
    400 
    401 }  // namespace base
    402