Coverage for /Syzygy/common/recursive_lock_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%53530.C++test

Line-by-line coverage:

   1    :  // Copyright 2014 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/common/recursive_lock.h"
  16    :  
  17    :  #include "base/memory/scoped_vector.h"
  18    :  #include "base/threading/simple_thread.h"
  19    :  #include "gtest/gtest.h"
  20    :  
  21    :  namespace common {
  22    :  
  23    :  namespace {
  24    :  
  25    :  // We use a thread-safe random function to avoid all of the various threads
  26    :  // consistently producing the exact same random values.
  27  E :  size_t Rand(size_t min, size_t max) {
  28  E :    static base::Lock lock;
  29  E :    base::AutoLock auto_lock(lock);
  30  E :    size_t r = rand();
  31  E :    double v = static_cast<double>(r) / static_cast<double>(RAND_MAX);
  32  E :    v *= max - min;
  33  E :    r = min + static_cast<size_t>(::round(v));
  34  E :    return r;
  35  E :  }
  36    :  
  37    :  // A thread that grabs a recursive lock repeatedly, to random recursion depths.
  38    :  class RecursiveLockTestRunner : public base::DelegateSimpleThread::Delegate {
  39    :   public:
  40  E :    RecursiveLockTestRunner(size_t lock_count, RecursiveLock* recursive_lock)
  41    :        : lock_count_(lock_count), recursive_lock_(recursive_lock) {
  42  E :    }
  43    :  
  44  E :    virtual void Run() {
  45    :      // The precision of 'Sleep' is in ticks, and we want to wait for 0 or 1
  46    :      // ticks.
  47    :      static const size_t kOneTickInMs = 15;
  48    :      static const size_t kMaxTryCount = 40;
  49    :  
  50    :      // Repeatedly grab the lock, with varying recursion depths.
  51  E :      while (lock_count_ > 0) {
  52  E :        ::Sleep(kOneTickInMs * Rand(0, 1));
  53    :  
  54    :        // Choose a random depth with which to acquire this thread.
  55  E :        size_t depth = Rand(1, 40);
  56  E :        for (size_t i = 0; i < depth; ++i) {
  57    :          // Every second time we acquire the lock we try it with 'try'.
  58  E :          if ((i % 2) == 0) {
  59    :            // Try to acquire a few times.
  60  E :            size_t try_count = 0;
  61  E :            while (try_count < kMaxTryCount && !recursive_lock_->Try()) {
  62  E :              ++try_count;
  63  E :              ::Sleep(kOneTickInMs * Rand(0, 1));
  64  E :            }
  65    :  
  66    :            // If we didn't acquire the lock by calling 'Try', then grab it
  67    :            // with a blocking acquisition.
  68  E :            if (try_count == kMaxTryCount)
  69  E :              recursive_lock_->Acquire();
  70  E :          } else {
  71    :            // Otherwise, simply block on the lock.
  72  E :            recursive_lock_->Acquire();
  73    :          }
  74  E :        }
  75    :  
  76    :        // Release the thread half of the number of times.
  77  E :        for (size_t i = 0; i < depth / 2; ++i)
  78  E :          recursive_lock_->Release();
  79    :  
  80    :        // Grab and release it a secondary time. This causes an 'up down up down'
  81    :        // motion on the recursion depth.
  82  E :        size_t depth1 = Rand(0, 20);
  83  E :        for (size_t i = 0; i < depth1; ++i)
  84  E :          recursive_lock_->Acquire();
  85  E :        for (size_t i = 0; i < depth1; ++i)
  86  E :          recursive_lock_->Release();
  87    :  
  88    :        // And release the rest of the initial acquisitions.
  89  E :        for (size_t i = depth / 2; i < depth; ++i)
  90  E :          recursive_lock_->Release();
  91    :  
  92  E :        --lock_count_;
  93  E :      }
  94  E :    }
  95    :  
  96    :   private:
  97    :    // The number of times this thread should grab the lock.
  98    :    size_t lock_count_;
  99    :    // The lock that is being grabbed.
 100    :    RecursiveLock* recursive_lock_;
 101    :  };
 102    :  
 103    :  }  // namespace
 104    :  
 105  E :  TEST(RecursiveLock, StressTest) {
 106    :    static const size_t kCyclesPerThread = 100;
 107    :    static const size_t kThreadCount = 50;
 108  E :    RecursiveLock lock;
 109    :  
 110  E :    lock.Acquire();
 111  E :    ScopedVector<RecursiveLockTestRunner> runners;
 112  E :    ScopedVector<base::DelegateSimpleThread> threads;
 113  E :    for (size_t i = 0; i < kThreadCount; ++i) {
 114  E :      runners.push_back(new RecursiveLockTestRunner(kCyclesPerThread, &lock));
 115    :      threads.push_back(new base::DelegateSimpleThread(runners.back(),
 116  E :                                                       "RecursiveLockTest"));
 117  E :      threads.back()->Start();
 118  E :    }
 119  E :    lock.Release();
 120    :  
 121  E :    for (size_t i = 0; i < threads.size(); ++i)
 122  E :      threads[i]->Join();
 123  E :  }
 124    :  
 125    :  }  // namespace common

Coverage information generated Thu Jan 14 17:40:38 2016.