Home | History | Annotate | Download | only in cctest
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "src/v8.h"
     29 
     30 #include "src/platform/condition-variable.h"
     31 #include "src/platform/time.h"
     32 #include "test/cctest/cctest.h"
     33 
     34 using namespace ::v8::internal;
     35 
     36 
     37 TEST(WaitForAfterNofityOnSameThread) {
     38   for (int n = 0; n < 10; ++n) {
     39     Mutex mutex;
     40     ConditionVariable cv;
     41 
     42     LockGuard<Mutex> lock_guard(&mutex);
     43 
     44     cv.NotifyOne();
     45     CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
     46 
     47     cv.NotifyAll();
     48     CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
     49   }
     50 }
     51 
     52 
     53 class ThreadWithMutexAndConditionVariable V8_FINAL : public Thread {
     54  public:
     55   ThreadWithMutexAndConditionVariable()
     56       : Thread("ThreadWithMutexAndConditionVariable"),
     57         running_(false), finished_(false) {}
     58   virtual ~ThreadWithMutexAndConditionVariable() {}
     59 
     60   virtual void Run() V8_OVERRIDE {
     61     LockGuard<Mutex> lock_guard(&mutex_);
     62     running_ = true;
     63     cv_.NotifyOne();
     64     while (running_) {
     65       cv_.Wait(&mutex_);
     66     }
     67     finished_ = true;
     68     cv_.NotifyAll();
     69   }
     70 
     71   bool running_;
     72   bool finished_;
     73   ConditionVariable cv_;
     74   Mutex mutex_;
     75 };
     76 
     77 
     78 TEST(MultipleThreadsWithSeparateConditionVariables) {
     79   static const int kThreadCount = 128;
     80   ThreadWithMutexAndConditionVariable threads[kThreadCount];
     81 
     82   for (int n = 0; n < kThreadCount; ++n) {
     83     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
     84     CHECK(!threads[n].running_);
     85     CHECK(!threads[n].finished_);
     86     threads[n].Start();
     87     // Wait for nth thread to start.
     88     while (!threads[n].running_) {
     89       threads[n].cv_.Wait(&threads[n].mutex_);
     90     }
     91   }
     92 
     93   for (int n = kThreadCount - 1; n >= 0; --n) {
     94     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
     95     CHECK(threads[n].running_);
     96     CHECK(!threads[n].finished_);
     97   }
     98 
     99   for (int n = 0; n < kThreadCount; ++n) {
    100     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
    101     CHECK(threads[n].running_);
    102     CHECK(!threads[n].finished_);
    103     // Tell the nth thread to quit.
    104     threads[n].running_ = false;
    105     threads[n].cv_.NotifyOne();
    106   }
    107 
    108   for (int n = kThreadCount - 1; n >= 0; --n) {
    109     // Wait for nth thread to quit.
    110     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
    111     while (!threads[n].finished_) {
    112       threads[n].cv_.Wait(&threads[n].mutex_);
    113     }
    114     CHECK(!threads[n].running_);
    115     CHECK(threads[n].finished_);
    116   }
    117 
    118   for (int n = 0; n < kThreadCount; ++n) {
    119     threads[n].Join();
    120     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
    121     CHECK(!threads[n].running_);
    122     CHECK(threads[n].finished_);
    123   }
    124 }
    125 
    126 
    127 class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread {
    128  public:
    129   ThreadWithSharedMutexAndConditionVariable()
    130       : Thread("ThreadWithSharedMutexAndConditionVariable"),
    131         running_(false), finished_(false), cv_(NULL), mutex_(NULL) {}
    132   virtual ~ThreadWithSharedMutexAndConditionVariable() {}
    133 
    134   virtual void Run() V8_OVERRIDE {
    135     LockGuard<Mutex> lock_guard(mutex_);
    136     running_ = true;
    137     cv_->NotifyAll();
    138     while (running_) {
    139       cv_->Wait(mutex_);
    140     }
    141     finished_ = true;
    142     cv_->NotifyAll();
    143   }
    144 
    145   bool running_;
    146   bool finished_;
    147   ConditionVariable* cv_;
    148   Mutex* mutex_;
    149 };
    150 
    151 
    152 TEST(MultipleThreadsWithSharedSeparateConditionVariables) {
    153   static const int kThreadCount = 128;
    154   ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
    155   ConditionVariable cv;
    156   Mutex mutex;
    157 
    158   for (int n = 0; n < kThreadCount; ++n) {
    159     threads[n].mutex_ = &mutex;
    160     threads[n].cv_ = &cv;
    161   }
    162 
    163   // Start all threads.
    164   {
    165     LockGuard<Mutex> lock_guard(&mutex);
    166     for (int n = 0; n < kThreadCount; ++n) {
    167       CHECK(!threads[n].running_);
    168       CHECK(!threads[n].finished_);
    169       threads[n].Start();
    170     }
    171   }
    172 
    173   // Wait for all threads to start.
    174   {
    175     LockGuard<Mutex> lock_guard(&mutex);
    176     for (int n = kThreadCount - 1; n >= 0; --n) {
    177       while (!threads[n].running_) {
    178         cv.Wait(&mutex);
    179       }
    180     }
    181   }
    182 
    183   // Make sure that all threads are running.
    184   {
    185     LockGuard<Mutex> lock_guard(&mutex);
    186     for (int n = 0; n < kThreadCount; ++n) {
    187       CHECK(threads[n].running_);
    188       CHECK(!threads[n].finished_);
    189     }
    190   }
    191 
    192   // Tell all threads to quit.
    193   {
    194     LockGuard<Mutex> lock_guard(&mutex);
    195     for (int n = kThreadCount - 1; n >= 0; --n) {
    196       CHECK(threads[n].running_);
    197       CHECK(!threads[n].finished_);
    198       // Tell the nth thread to quit.
    199       threads[n].running_ = false;
    200     }
    201     cv.NotifyAll();
    202   }
    203 
    204   // Wait for all threads to quit.
    205   {
    206     LockGuard<Mutex> lock_guard(&mutex);
    207     for (int n = 0; n < kThreadCount; ++n) {
    208       while (!threads[n].finished_) {
    209         cv.Wait(&mutex);
    210       }
    211     }
    212   }
    213 
    214   // Make sure all threads are finished.
    215   {
    216     LockGuard<Mutex> lock_guard(&mutex);
    217     for (int n = kThreadCount - 1; n >= 0; --n) {
    218       CHECK(!threads[n].running_);
    219       CHECK(threads[n].finished_);
    220     }
    221   }
    222 
    223   // Join all threads.
    224   for (int n = 0; n < kThreadCount; ++n) {
    225     threads[n].Join();
    226   }
    227 }
    228 
    229 
    230 class LoopIncrementThread V8_FINAL : public Thread {
    231  public:
    232   LoopIncrementThread(int rem,
    233                       int* counter,
    234                       int limit,
    235                       int thread_count,
    236                       ConditionVariable* cv,
    237                       Mutex* mutex)
    238       : Thread("LoopIncrementThread"), rem_(rem), counter_(counter),
    239         limit_(limit), thread_count_(thread_count), cv_(cv), mutex_(mutex) {
    240     CHECK_LT(rem, thread_count);
    241     CHECK_EQ(0, limit % thread_count);
    242   }
    243 
    244   virtual void Run() V8_OVERRIDE {
    245     int last_count = -1;
    246     while (true) {
    247       LockGuard<Mutex> lock_guard(mutex_);
    248       int count = *counter_;
    249       while (count % thread_count_ != rem_ && count < limit_) {
    250         cv_->Wait(mutex_);
    251         count = *counter_;
    252       }
    253       if (count >= limit_) break;
    254       CHECK_EQ(*counter_, count);
    255       if (last_count != -1) {
    256         CHECK_EQ(last_count + (thread_count_ - 1), count);
    257       }
    258       count++;
    259       *counter_ = count;
    260       last_count = count;
    261       cv_->NotifyAll();
    262     }
    263   }
    264 
    265  private:
    266   const int rem_;
    267   int* counter_;
    268   const int limit_;
    269   const int thread_count_;
    270   ConditionVariable* cv_;
    271   Mutex* mutex_;
    272 };
    273 
    274 
    275 TEST(LoopIncrement) {
    276   static const int kMaxThreadCount = 16;
    277   Mutex mutex;
    278   ConditionVariable cv;
    279   for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
    280     int limit = thread_count * 100;
    281     int counter = 0;
    282 
    283     // Setup the threads.
    284     Thread** threads = new Thread*[thread_count];
    285     for (int n = 0; n < thread_count; ++n) {
    286       threads[n] = new LoopIncrementThread(
    287           n, &counter, limit, thread_count, &cv, &mutex);
    288     }
    289 
    290     // Start all threads.
    291     for (int n = thread_count - 1; n >= 0; --n) {
    292       threads[n]->Start();
    293     }
    294 
    295     // Join and cleanup all threads.
    296     for (int n = 0; n < thread_count; ++n) {
    297       threads[n]->Join();
    298       delete threads[n];
    299     }
    300     delete[] threads;
    301 
    302     CHECK_EQ(limit, counter);
    303   }
    304 }
    305