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