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 : // An implementation of a size-limited quarantine. This encapsulates the
16 : // logic for maintaining a size invariant over the items in a quarantine.
17 :
18 : #ifndef SYZYGY_AGENT_ASAN_QUARANTINES_SIZE_LIMITED_QUARANTINE_H_
19 : #define SYZYGY_AGENT_ASAN_QUARANTINES_SIZE_LIMITED_QUARANTINE_H_
20 :
21 : #include "base/atomicops.h"
22 : #include "base/synchronization/lock.h"
23 : #include "syzygy/agent/asan/quarantine.h"
24 :
25 : namespace agent {
26 : namespace asan {
27 : namespace quarantines {
28 :
29 : // Provides both the size of the quarantine and the number of elements it
30 : // contains. Both of these are accessed behind a lock, to ensure their
31 : // consistency. Hence, the lock must be acquired (by calling Lock) before any
32 : // other operation is performed. The lock should be returned (by calling Unlock)
33 : // as soon as possible to minimize the locked time.
34 : class QuarantineSizeCount {
35 : public:
36 : // Default constructor that sets the size and count to 0.
37 E : QuarantineSizeCount() : size_(0), count_(0) {}
38 :
39 : // Must be called before any other operation to acquire the lock.
40 E : void Lock() { lock_.Acquire(); }
41 :
42 : // Releases the lock.
43 E : void Unlock() {
44 E : lock_.AssertAcquired();
45 E : lock_.Release();
46 E : }
47 :
48 : // @returns the size.
49 E : int32 size() const {
50 E : lock_.AssertAcquired();
51 E : return size_;
52 E : }
53 :
54 : // @returns the count.
55 E : int32 count() const {
56 E : lock_.AssertAcquired();
57 E : return count_;
58 E : }
59 :
60 : // Increments the size and count (accepts negative values for decrementing).
61 : // @param size_delta The delta by which the size is incremented.
62 : // @param count_delta The delta by which the count is incremented.
63 E : void Increment(int32 size_delta, int32 count_delta) {
64 E : lock_.AssertAcquired();
65 E : size_ += size_delta;
66 E : count_ += count_delta;
67 E : }
68 :
69 : private:
70 : // The current size of the quarantine.
71 : int32 size_;
72 : // The number of elements in the quarantine.
73 : int32 count_;
74 : // Single lock that's used for both |size_| and |count_|.
75 : base::Lock lock_;
76 : };
77 :
78 : // An automatic lock on QuarantineSizeCount.
79 : class ScopedQuarantineSizeCountLock {
80 : public:
81 : // Constructor. Automatically lock the quarantine.
82 E : explicit ScopedQuarantineSizeCountLock(QuarantineSizeCount& size_count)
83 : : size_count_(size_count) {
84 E : size_count_.Lock();
85 E : }
86 :
87 : // Destructor. Automatically unlock the quarantine.
88 E : ~ScopedQuarantineSizeCountLock() { size_count_.Unlock(); }
89 :
90 : private:
91 : // The QuarantineSizeCount that this holds.
92 : QuarantineSizeCount& size_count_;
93 :
94 : DISALLOW_COPY_AND_ASSIGN(ScopedQuarantineSizeCountLock);
95 : };
96 :
97 : // A partial implementation of a size-limited quarantine. This quarantine
98 : // obeys a simple invariant: the sum of object weights within it must be
99 : // less than a certain threshold, and all objects within it must be smaller
100 : // than another given threshold.
101 : //
102 : // Provides implementations of QuarantineInterface Push/Pop/Empty methods.
103 : // Expects the derived class to provide implementations for a few methods:
104 : //
105 : // bool PushImpl(const ObjectType& object);
106 : // bool PopImpl(ObjectType* object);
107 : // void EmptyImpl(ObjectVector* object);
108 : //
109 : // Calculates the sizes of objects using the provided SizeFunctor. This
110 : // must satisfy the following interface:
111 : //
112 : // struct SizeFunctor {
113 : // size_t operator()(const ObjectType& object);
114 : // };
115 : //
116 : // @tparam ObjectType The type of object stored in the quarantine.
117 : // @tparam SizeFunctorType The size functor that will be used to extract
118 : // a size from an object.
119 : template<typename ObjectType, typename SizeFunctorType>
120 : class SizeLimitedQuarantineImpl : public QuarantineInterface<ObjectType> {
121 : public:
122 : typedef SizeFunctorType SizeFunctor;
123 :
124 : static const size_t kUnboundedSize = SIZE_MAX;
125 :
126 : // Constructor. Initially the quarantine has unlimited capacity.
127 : SizeLimitedQuarantineImpl()
128 : : max_object_size_(kUnboundedSize),
129 : max_quarantine_size_(kUnboundedSize),
130 E : size_functor_() {
131 E : }
132 :
133 : // Constructor. Initially the quarantine has unlimited capacity.
134 : // @param size_functor The size functor to be used. This will be copied
135 : // into the classes member size functor.
136 : explicit SizeLimitedQuarantineImpl(const SizeFunctor& size_functor)
137 : : max_object_size_(kUnboundedSize),
138 : max_quarantine_size_(kUnboundedSize),
139 : size_functor_(size_functor) {
140 : }
141 :
142 : // Virtual destructor.
143 E : virtual ~SizeLimitedQuarantineImpl() { }
144 :
145 : // Sets the maximum object size. This only gates the entry of future
146 : // objects to 'Push', and does not invalidate overly objects already in
147 : // the quarantine.
148 : // @param max_object_size The maximum size of any single object in the
149 : // quarantine. Use kUnboundedSize for unlimited (no max).
150 E : void set_max_object_size(size_t max_object_size) {
151 E : max_object_size_ = max_object_size;
152 E : }
153 :
154 : // Sets the maximum quarantine size. This may cause the quarantine
155 : // invariant to be immediately invalidated, requiring calls to 'Pop'.
156 : // @param max_quarantine_size The maximum size of the entire quarantine.
157 : // Use kUnboundedSize for unlimited (no max).
158 E : void set_max_quarantine_size(size_t max_quarantine_size) {
159 E : max_quarantine_size_ = max_quarantine_size;
160 E : }
161 :
162 : // @returns the maximum object size.
163 E : size_t max_object_size() const { return max_object_size_; }
164 :
165 : // @returns the maximum quarantine size.
166 E : size_t max_quarantine_size() const { return max_quarantine_size_; }
167 :
168 : // @returns the current size of the quarantine.
169 : // @note that this function could be racing with a push/pop operation and
170 : // return a stale value. It should only be used when this is acceptable (in
171 : // tests for example).
172 E : size_t size() {
173 E : ScopedQuarantineSizeCountLock size_count_lock(size_count_);
174 E : return size_count_.size();
175 E : }
176 :
177 : // @name QuarantineInterface implementation.
178 : // @note that GetCount could be racing with a push/pop operation and return a
179 : // stale value. It should only be used when this is acceptable (in tests for
180 : // example).
181 : // @{
182 : virtual bool Push(const Object& object);
183 : virtual bool Pop(Object* object);
184 : virtual void Empty(ObjectVector* objects);
185 : virtual size_t GetCount();
186 : virtual size_t GetLockId(const Object& object);
187 : virtual void Lock(size_t id);
188 : virtual void Unlock(size_t id);
189 : // @}
190 :
191 : protected:
192 : // @name SizeLimitedQuarantine interface.
193 : // @{
194 : virtual bool PushImpl(const Object& object) = 0;
195 : virtual bool PopImpl(Object* object) = 0;
196 : virtual void EmptyImpl(ObjectVector* objects) = 0;
197 : virtual size_t GetLockIdImpl(const Object& object) = 0;
198 : virtual void LockImpl(size_t id) = 0;
199 : virtual void UnlockImpl(size_t id) = 0;
200 : // @}
201 :
202 : // Parameters controlling the quarantine invariant.
203 : size_t max_object_size_;
204 : size_t max_quarantine_size_;
205 :
206 : QuarantineSizeCount size_count_;
207 :
208 : // The size functor.
209 : SizeFunctor size_functor_;
210 :
211 : private:
212 : DISALLOW_COPY_AND_ASSIGN(SizeLimitedQuarantineImpl);
213 : };
214 :
215 : } // namespace quarantines
216 : } // namespace asan
217 : } // namespace agent
218 :
219 : #include "syzygy/agent/asan/quarantines/size_limited_quarantine_impl.h"
220 :
221 : #endif // SYZYGY_AGENT_ASAN_QUARANTINES_SIZE_LIMITED_QUARANTINE_H_
|