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 : // Utility functions for spending a fixed amount of time trying to acquire
16 : // a base::Lock (or any lock with the same API).
17 :
18 : #ifndef SYZYGY_AGENT_ASAN_TIMED_TRY_IMPL_H_
19 : #define SYZYGY_AGENT_ASAN_TIMED_TRY_IMPL_H_
20 :
21 : #ifndef SYZYGY_AGENT_ASAN_TIMED_TRY_H_
22 : #error Meant to be included from timed_try.h only.
23 : #endif
24 :
25 : #include "base/logging.h"
26 : #include "base/time/time.h"
27 : #include "syzygy/agent/asan/heap.h"
28 :
29 : namespace agent {
30 : namespace asan {
31 :
32 : namespace detail {
33 :
34 : // A simple adapter for base::Lock-like locks (Try and Release).
35 : template<typename LockType>
36 : struct BaseLockAdapter {
37 E : bool Try(LockType* lock) {
38 E : DCHECK_NE(static_cast<LockType*>(NULL), lock);
39 E : return lock->Try();
40 E : }
41 :
42 E : void Release(LockType* lock) {
43 E : DCHECK_NE(static_cast<LockType*>(NULL), lock);
44 E : lock->Release();
45 E : }
46 : };
47 :
48 : // A lock adapter for HeapInterface objects.
49 : struct HeapInterfaceAdapter {
50 E : bool Try(HeapInterface* heap) {
51 E : DCHECK_NE(static_cast<HeapInterface*>(NULL), heap);
52 E : return heap->TryLock();
53 E : }
54 :
55 E : void Release(HeapInterface* heap) {
56 E : DCHECK_NE(static_cast<HeapInterface*>(NULL), heap);
57 E : heap->Unlock();
58 E : }
59 : };
60 :
61 : // A lock adapter selector. By default selects BaseLockAdapter, and expects
62 : // the lock to implement 'Try' and 'Release'.
63 : template<typename LockType>
64 : struct SelectLockAdapter {
65 : typedef BaseLockAdapter<LockType> type;
66 : };
67 :
68 : // A specialization that selects HeapInterfaceAdapter for HeapInterface objects.
69 : template<>
70 : struct SelectLockAdapter<HeapInterface> {
71 : typedef HeapInterfaceAdapter type;
72 : };
73 :
74 : } // namespace detail
75 :
76 : template<typename LockType>
77 E : bool TimedTry(base::TimeDelta delta, LockType* lock) {
78 E : DCHECK_NE(static_cast<LockType*>(NULL), lock);
79 :
80 : // Try at least once, even if |delta| is zero or negative.
81 : detail::SelectLockAdapter<LockType>::type adapter;
82 E : if (adapter.Try(lock))
83 E : return true;
84 :
85 : // Try repeatedly, until timeout.
86 E : base::Time end = base::Time::Now() + delta;
87 E : while (base::Time::Now() < end) {
88 : // Spin a bunch of times.
89 E : for (size_t i = 0; i < 100; ++i)
90 E : if (adapter.Try(lock))
91 E : return true;
92 :
93 : // Cede the processor to another thread, hoping the lock will become
94 : // available at some point.
95 E : ::SwitchToThread();
96 E : }
97 :
98 E : return false;
99 E : }
100 :
101 : template<typename LockType>
102 : AutoTimedTry<LockType>::AutoTimedTry(
103 : base::TimeDelta delta, LockType* lock)
104 E : : lock_(lock) {
105 E : DCHECK_NE(static_cast<LockType*>(NULL), lock);
106 E : is_acquired_ = TimedTry<LockType>(delta, lock);
107 E : }
108 :
109 : template<typename LockType>
110 E : AutoTimedTry<LockType>::~AutoTimedTry() {
111 : detail::SelectLockAdapter<LockType>::type adapter;
112 E : if (is_acquired_)
113 E : adapter.Release(lock_);
114 E : }
115 :
116 : template<typename LockType>
117 E : bool AutoTimedTry<LockType>::is_acquired() const {
118 E : return is_acquired_;
119 E : }
120 :
121 : } // namespace asan
122 : } // namespace agent
123 :
124 : #endif // SYZYGY_AGENT_ASAN_TIMED_TRY_IMPL_H_
|