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/agent/asan/timed_try.h"
16 :
17 : #include "base/synchronization/condition_variable.h"
18 : #include "base/synchronization/lock.h"
19 : #include "base/threading/simple_thread.h"
20 : #include "base/time/time.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/agent/asan/heaps/win_heap.h"
23 : #include "syzygy/common/recursive_lock.h"
24 :
25 : namespace agent {
26 : namespace asan {
27 :
28 : namespace {
29 :
30 : // An adapater for allowing a base::Lock to be used in the unittest.
31 : template<typename LockType>
32 : struct BaseLockAdapter {
33 : typedef LockType ConcreteLockType;
34 : typedef LockType AbstractLockType;
35 :
36 E : void AssertAcquired(LockType* lock) {
37 E : lock->AssertAcquired();
38 E : }
39 :
40 E : void Acquire(LockType* lock) {
41 E : lock->Acquire();
42 E : }
43 :
44 E : void Release(LockType* lock) {
45 E : lock->Release();
46 E : }
47 :
48 : void Try(LockType* lock) {
49 : return lock->Try();
50 : }
51 : };
52 :
53 :
54 : // An adapater for allowing a HeapInterface object to be used in the
55 : // unittest.
56 : template<typename HeapType>
57 : struct HeapAdapter {
58 : typedef HeapType ConcreteLockType;
59 : typedef HeapInterface AbstractLockType;
60 :
61 E : void AssertAcquired(HeapType* heap) {
62 E : }
63 :
64 E : void Acquire(HeapType* heap) {
65 E : heap->Lock();
66 E : }
67 :
68 E : void Release(HeapType* heap) {
69 E : heap->Unlock();
70 E : }
71 :
72 : void Try(HeapType* heap) {
73 : return heap->TryLock();
74 : }
75 : };
76 :
77 :
78 : // A thread body that acquires a lock, waits a certain amount of time, then
79 : // releases it. Signals when it has acquired the lock for unittest
80 : // synchronization purposes.
81 : template<typename LockAdapter>
82 : class TimedTryTestRunner : public base::DelegateSimpleThread::Delegate {
83 : public:
84 : typedef typename LockAdapter::ConcreteLockType LockType;
85 :
86 : TimedTryTestRunner(base::TimeDelta delta, LockType* lock)
87 E : : cv_(&cv_lock_), held_(false), delta_(delta), lock_(lock) {
88 E : DCHECK_NE(static_cast<LockType*>(NULL), lock);
89 E : }
90 :
91 E : virtual void Run() {
92 : LockAdapter adapter;
93 E : adapter.Acquire(lock_);
94 :
95 : // Notify that the lock has been acquired.
96 : {
97 E : base::AutoLock lock(cv_lock_);
98 E : held_ = true;
99 E : cv_.Signal();
100 E : }
101 :
102 E : base::Time end = base::Time::Now() + delta_;
103 E : while (true) {
104 E : base::Time now = base::Time::Now();
105 E : if (now >= end)
106 E : break;
107 E : base::TimeDelta remaining = end - now;
108 E : ::Sleep(remaining.InMillisecondsRoundedUp());
109 E : }
110 :
111 E : adapter.Release(lock_);
112 E : }
113 :
114 E : void WaitUntilHeld() {
115 E : base::AutoLock auto_lock(cv_lock_);
116 E : if (held_)
117 i : return;
118 E : cv_.Wait();
119 E : }
120 :
121 : private:
122 : // Used for signalling when the lock has been acquired.
123 : base::Lock cv_lock_;
124 : base::ConditionVariable cv_;
125 : bool held_;
126 :
127 : base::TimeDelta delta_;
128 : LockType* lock_;
129 :
130 : DISALLOW_COPY_AND_ASSIGN(TimedTryTestRunner);
131 : };
132 :
133 E : base::TimeDelta kDelay(base::TimeDelta::FromMilliseconds(100));
134 :
135 : template <typename LockAdapter>
136 E : void TimedTryTestImpl() {
137 : typedef typename LockAdapter::ConcreteLockType LockType;
138 : typedef typename LockAdapter::AbstractLockType LockInterfaceType;
139 : LockAdapter adapter;
140 E : LockType lock;
141 :
142 E : TimedTryTestRunner<LockAdapter> runner(kDelay * 2, &lock);
143 E : base::DelegateSimpleThread thread(&runner, "TimedTryTestRunner");
144 :
145 : // Grab the lock.
146 E : EXPECT_TRUE(TimedTry<LockInterfaceType>(kDelay, &lock));
147 E : adapter.AssertAcquired(&lock);
148 :
149 : // Try to grab the lock but expect a timeout.
150 E : base::Time t0 = base::Time::Now();
151 E : thread.Start();
152 E : adapter.Release(&lock);
153 E : runner.WaitUntilHeld();
154 E : ASSERT_FALSE(TimedTry<LockInterfaceType>(kDelay, &lock));
155 :
156 : // Try to grab the lock again, expecting success this time.
157 E : ASSERT_TRUE(TimedTry<LockInterfaceType>(kDelay * 10, &lock));
158 E : adapter.Release(&lock);
159 E : base::Time t1 = base::Time::Now();
160 E : EXPECT_LE(kDelay * 2, t1 - t0);
161 :
162 E : thread.Join();
163 E : }
164 :
165 : template <typename LockAdapter>
166 E : void AutoTimedTryTestImpl() {
167 : typedef typename LockAdapter::ConcreteLockType LockType;
168 : typedef typename LockAdapter::AbstractLockType LockInterfaceType;
169 E : LockType lock;
170 :
171 E : TimedTryTestRunner<LockAdapter> runner(kDelay * 2, &lock);
172 E : base::DelegateSimpleThread thread(&runner, "TimedTryTestRunner");
173 :
174 E : base::Time t0;
175 : {
176 E : AutoTimedTry<LockInterfaceType> timed_try(kDelay, &lock);
177 E : EXPECT_TRUE(timed_try.is_acquired());
178 E : t0 = base::Time::Now();
179 E : thread.Start();
180 E : }
181 E : runner.WaitUntilHeld();
182 :
183 : // Try to grab the lock, but expect it to fail as the lock will be held
184 : // longer than we try.
185 : {
186 E : AutoTimedTry<LockInterfaceType> timed_try(kDelay, &lock);
187 E : EXPECT_FALSE(timed_try.is_acquired());
188 E : }
189 :
190 : // Try to grab the lock and expect it to succeed, as the wait is longer than
191 : // the lock will be held.
192 : {
193 E : AutoTimedTry<LockInterfaceType> timed_try(kDelay * 10, &lock);
194 E : base::Time t1 = base::Time::Now();
195 E : EXPECT_LE(kDelay * 2, t1 - t0);
196 E : }
197 :
198 E : thread.Join();
199 E : }
200 :
201 : } // namespace
202 :
203 E : TEST(TimedTryTest, BaseLock) {
204 : typedef BaseLockAdapter<base::Lock> LockAdapter;
205 E : ASSERT_NO_FATAL_FAILURE(TimedTryTestImpl<LockAdapter>());
206 E : }
207 :
208 E : TEST(AutoTimedTryTest, BaseLock) {
209 : typedef BaseLockAdapter<base::Lock> LockAdapter;
210 E : ASSERT_NO_FATAL_FAILURE(AutoTimedTryTestImpl<LockAdapter>());
211 E : }
212 :
213 E : TEST(TimedTryTest, CommonRecursiveLock) {
214 : typedef BaseLockAdapter<::common::RecursiveLock> LockAdapter;
215 E : ASSERT_NO_FATAL_FAILURE(TimedTryTestImpl<LockAdapter>());
216 E : }
217 :
218 E : TEST(AutoTimedTryTest, CommonRecursiveLock) {
219 : typedef BaseLockAdapter<::common::RecursiveLock> LockAdapter;
220 E : ASSERT_NO_FATAL_FAILURE(AutoTimedTryTestImpl<LockAdapter>());
221 E : }
222 :
223 E : TEST(TimedTryTest, HeapInterface) {
224 : typedef HeapAdapter<heaps::WinHeap> LockAdapter;
225 E : ASSERT_NO_FATAL_FAILURE(TimedTryTestImpl<LockAdapter>());
226 E : }
227 :
228 E : TEST(AutoTimedTryTest, HeapInterface) {
229 : typedef HeapAdapter<heaps::WinHeap> LockAdapter;
230 E : ASSERT_NO_FATAL_FAILURE(AutoTimedTryTestImpl<LockAdapter>());
231 E : }
232 :
233 : } // namespace asan
234 : } // namespace agent
|