LCOV - code coverage report
Current view: top level - test/unittests/base/platform - condition-variable-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 134 134 100.0 %
Date: 2019-04-18 Functions: 17 25 68.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project 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 "src/base/platform/condition-variable.h"
       6             : 
       7             : #include "src/base/platform/platform.h"
       8             : #include "src/base/platform/time.h"
       9             : #include "testing/gtest/include/gtest/gtest.h"
      10             : 
      11             : namespace v8 {
      12             : namespace base {
      13             : 
      14       15418 : TEST(ConditionVariable, WaitForAfterNofityOnSameThread) {
      15          21 :   for (int n = 0; n < 10; ++n) {
      16          20 :     Mutex mutex;
      17          20 :     ConditionVariable cv;
      18             : 
      19             :     MutexGuard lock_guard(&mutex);
      20             : 
      21          10 :     cv.NotifyOne();
      22          20 :     EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
      23             : 
      24          10 :     cv.NotifyAll();
      25          20 :     EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
      26             :   }
      27           1 : }
      28             : 
      29             : 
      30             : namespace {
      31             : 
      32         128 : class ThreadWithMutexAndConditionVariable final : public Thread {
      33             :  public:
      34         128 :   ThreadWithMutexAndConditionVariable()
      35             :       : Thread(Options("ThreadWithMutexAndConditionVariable")),
      36             :         running_(false),
      37         128 :         finished_(false) {}
      38             : 
      39         128 :   void Run() override {
      40         128 :     MutexGuard lock_guard(&mutex_);
      41         128 :     running_ = true;
      42         128 :     cv_.NotifyOne();
      43         384 :     while (running_) {
      44         128 :       cv_.Wait(&mutex_);
      45             :     }
      46         128 :     finished_ = true;
      47         128 :     cv_.NotifyAll();
      48         128 :   }
      49             : 
      50             :   bool running_;
      51             :   bool finished_;
      52             :   ConditionVariable cv_;
      53             :   Mutex mutex_;
      54             : };
      55             : 
      56             : }  // namespace
      57             : 
      58             : 
      59       15418 : TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) {
      60             :   static const int kThreadCount = 128;
      61         258 :   ThreadWithMutexAndConditionVariable threads[kThreadCount];
      62             : 
      63         257 :   for (int n = 0; n < kThreadCount; ++n) {
      64         128 :     MutexGuard lock_guard(&threads[n].mutex_);
      65         256 :     EXPECT_FALSE(threads[n].running_);
      66         256 :     EXPECT_FALSE(threads[n].finished_);
      67         128 :     threads[n].Start();
      68             :     // Wait for nth thread to start.
      69         384 :     while (!threads[n].running_) {
      70         128 :       threads[n].cv_.Wait(&threads[n].mutex_);
      71             :     }
      72             :   }
      73             : 
      74         257 :   for (int n = kThreadCount - 1; n >= 0; --n) {
      75         128 :     MutexGuard lock_guard(&threads[n].mutex_);
      76         128 :     EXPECT_TRUE(threads[n].running_);
      77         256 :     EXPECT_FALSE(threads[n].finished_);
      78             :   }
      79             : 
      80         257 :   for (int n = 0; n < kThreadCount; ++n) {
      81         128 :     MutexGuard lock_guard(&threads[n].mutex_);
      82         128 :     EXPECT_TRUE(threads[n].running_);
      83         256 :     EXPECT_FALSE(threads[n].finished_);
      84             :     // Tell the nth thread to quit.
      85         128 :     threads[n].running_ = false;
      86         128 :     threads[n].cv_.NotifyOne();
      87             :   }
      88             : 
      89         257 :   for (int n = kThreadCount - 1; n >= 0; --n) {
      90             :     // Wait for nth thread to quit.
      91         128 :     MutexGuard lock_guard(&threads[n].mutex_);
      92         132 :     while (!threads[n].finished_) {
      93           2 :       threads[n].cv_.Wait(&threads[n].mutex_);
      94             :     }
      95         256 :     EXPECT_FALSE(threads[n].running_);
      96         128 :     EXPECT_TRUE(threads[n].finished_);
      97             :   }
      98             : 
      99         257 :   for (int n = 0; n < kThreadCount; ++n) {
     100         128 :     threads[n].Join();
     101         128 :     MutexGuard lock_guard(&threads[n].mutex_);
     102         256 :     EXPECT_FALSE(threads[n].running_);
     103         128 :     EXPECT_TRUE(threads[n].finished_);
     104             :   }
     105           1 : }
     106             : 
     107             : 
     108             : namespace {
     109             : 
     110         128 : class ThreadWithSharedMutexAndConditionVariable final : public Thread {
     111             :  public:
     112             :   ThreadWithSharedMutexAndConditionVariable()
     113             :       : Thread(Options("ThreadWithSharedMutexAndConditionVariable")),
     114             :         running_(false),
     115             :         finished_(false),
     116             :         cv_(nullptr),
     117         128 :         mutex_(nullptr) {}
     118             : 
     119         127 :   void Run() override {
     120         127 :     MutexGuard lock_guard(mutex_);
     121         128 :     running_ = true;
     122         128 :     cv_->NotifyAll();
     123        1924 :     while (running_) {
     124         898 :       cv_->Wait(mutex_);
     125             :     }
     126         128 :     finished_ = true;
     127         128 :     cv_->NotifyAll();
     128         128 :   }
     129             : 
     130             :   bool running_;
     131             :   bool finished_;
     132             :   ConditionVariable* cv_;
     133             :   Mutex* mutex_;
     134             : };
     135             : 
     136             : }  // namespace
     137             : 
     138             : 
     139       15418 : TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) {
     140             :   static const int kThreadCount = 128;
     141         386 :   ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
     142           2 :   ConditionVariable cv;
     143           2 :   Mutex mutex;
     144             : 
     145         257 :   for (int n = 0; n < kThreadCount; ++n) {
     146         128 :     threads[n].mutex_ = &mutex;
     147         128 :     threads[n].cv_ = &cv;
     148             :   }
     149             : 
     150             :   // Start all threads.
     151             :   {
     152             :     MutexGuard lock_guard(&mutex);
     153         257 :     for (int n = 0; n < kThreadCount; ++n) {
     154         256 :       EXPECT_FALSE(threads[n].running_);
     155         256 :       EXPECT_FALSE(threads[n].finished_);
     156         128 :       threads[n].Start();
     157             :     }
     158             :   }
     159             : 
     160             :   // Wait for all threads to start.
     161             :   {
     162             :     MutexGuard lock_guard(&mutex);
     163         257 :     for (int n = kThreadCount - 1; n >= 0; --n) {
     164         144 :       while (!threads[n].running_) {
     165           8 :         cv.Wait(&mutex);
     166             :       }
     167             :     }
     168             :   }
     169             : 
     170             :   // Make sure that all threads are running.
     171             :   {
     172             :     MutexGuard lock_guard(&mutex);
     173         257 :     for (int n = 0; n < kThreadCount; ++n) {
     174         128 :       EXPECT_TRUE(threads[n].running_);
     175         256 :       EXPECT_FALSE(threads[n].finished_);
     176             :     }
     177             :   }
     178             : 
     179             :   // Tell all threads to quit.
     180             :   {
     181             :     MutexGuard lock_guard(&mutex);
     182         257 :     for (int n = kThreadCount - 1; n >= 0; --n) {
     183         128 :       EXPECT_TRUE(threads[n].running_);
     184         256 :       EXPECT_FALSE(threads[n].finished_);
     185             :       // Tell the nth thread to quit.
     186         128 :       threads[n].running_ = false;
     187             :     }
     188           1 :     cv.NotifyAll();
     189             :   }
     190             : 
     191             :   // Wait for all threads to quit.
     192             :   {
     193             :     MutexGuard lock_guard(&mutex);
     194         257 :     for (int n = 0; n < kThreadCount; ++n) {
     195         150 :       while (!threads[n].finished_) {
     196          11 :         cv.Wait(&mutex);
     197             :       }
     198             :     }
     199             :   }
     200             : 
     201             :   // Make sure all threads are finished.
     202             :   {
     203             :     MutexGuard lock_guard(&mutex);
     204         257 :     for (int n = kThreadCount - 1; n >= 0; --n) {
     205         256 :       EXPECT_FALSE(threads[n].running_);
     206         128 :       EXPECT_TRUE(threads[n].finished_);
     207             :     }
     208             :   }
     209             : 
     210             :   // Join all threads.
     211         257 :   for (int n = 0; n < kThreadCount; ++n) {
     212         128 :     threads[n].Join();
     213             :   }
     214           1 : }
     215             : 
     216             : 
     217             : namespace {
     218             : 
     219         120 : class LoopIncrementThread final : public Thread {
     220             :  public:
     221         120 :   LoopIncrementThread(int rem, int* counter, int limit, int thread_count,
     222             :                       ConditionVariable* cv, Mutex* mutex)
     223             :       : Thread(Options("LoopIncrementThread")),
     224             :         rem_(rem),
     225             :         counter_(counter),
     226             :         limit_(limit),
     227             :         thread_count_(thread_count),
     228             :         cv_(cv),
     229         120 :         mutex_(mutex) {
     230         120 :     EXPECT_LT(rem, thread_count);
     231         240 :     EXPECT_EQ(0, limit % thread_count);
     232         120 :   }
     233             : 
     234         120 :   void Run() override {
     235             :     int last_count = -1;
     236             :     while (true) {
     237        1320 :       MutexGuard lock_guard(mutex_);
     238        1320 :       int count = *counter_;
     239       14290 :       while (count % thread_count_ != rem_ && count < limit_) {
     240        6485 :         cv_->Wait(mutex_);
     241        6485 :         count = *counter_;
     242             :       }
     243        1320 :       if (count >= limit_) break;
     244        2400 :       EXPECT_EQ(*counter_, count);
     245        1200 :       if (last_count != -1) {
     246        2160 :         EXPECT_EQ(last_count + (thread_count_ - 1), count);
     247             :       }
     248        1200 :       count++;
     249        1200 :       *counter_ = count;
     250        1200 :       last_count = count;
     251        1200 :       cv_->NotifyAll();
     252             :     }
     253         120 :   }
     254             : 
     255             :  private:
     256             :   const int rem_;
     257             :   int* counter_;
     258             :   const int limit_;
     259             :   const int thread_count_;
     260             :   ConditionVariable* cv_;
     261             :   Mutex* mutex_;
     262             : };
     263             : 
     264             : }  // namespace
     265             : 
     266             : 
     267       15418 : TEST(ConditionVariable, LoopIncrement) {
     268             :   static const int kMaxThreadCount = 16;
     269           2 :   Mutex mutex;
     270           2 :   ConditionVariable cv;
     271          31 :   for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
     272          15 :     int limit = thread_count * 10;
     273          15 :     int counter = 0;
     274             : 
     275             :     // Setup the threads.
     276          15 :     Thread** threads = new Thread* [thread_count];
     277         255 :     for (int n = 0; n < thread_count; ++n) {
     278         120 :       threads[n] = new LoopIncrementThread(n, &counter, limit, thread_count,
     279         240 :                                            &cv, &mutex);
     280             :     }
     281             : 
     282             :     // Start all threads.
     283         135 :     for (int n = thread_count - 1; n >= 0; --n) {
     284         120 :       threads[n]->Start();
     285             :     }
     286             : 
     287             :     // Join and cleanup all threads.
     288         255 :     for (int n = 0; n < thread_count; ++n) {
     289         120 :       threads[n]->Join();
     290         120 :       delete threads[n];
     291             :     }
     292          15 :     delete[] threads;
     293             : 
     294          15 :     EXPECT_EQ(limit, counter);
     295             :   }
     296           1 : }
     297             : 
     298             : }  // namespace base
     299        9249 : }  // namespace v8

Generated by: LCOV version 1.10