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 : // Declares a recursive lock primitive. This lock is necessary when emulating
16 : // certain Windows primitives, where these locks are common.
17 :
18 : #ifndef SYZYGY_COMMON_RECURSIVE_LOCK_H_
19 : #define SYZYGY_COMMON_RECURSIVE_LOCK_H_
20 :
21 : #include "base/synchronization/condition_variable.h"
22 : #include "base/synchronization/lock.h"
23 :
24 : namespace common {
25 :
26 : // A recursive lock allows multiple acquisitions of the lock from the same
27 : // thread, keeping track of the number of acquisitions. Only once the lock has
28 : // been released the same number of times does it return to the unlocked state.
29 : class RecursiveLock {
30 : public:
31 : // Constructor.
32 : RecursiveLock();
33 :
34 : // Raises an exception/breakpoint under debug builds if the lock is not
35 : // acquired. Optimized away in release builds.
36 : void AssertAcquired();
37 :
38 : // Acquires the lock, blocking until it is available. This must be followed
39 : // at some point by a matching call to 'Release' from the same thread.
40 : void Acquire();
41 :
42 : // Releases the lock. This can only be called from the thread that currently
43 : // owns the lock.
44 : void Release();
45 :
46 : // Attempts to acquire the lock, without blocking.
47 : // @returns true if the attempt was successful (the lock is now owned by the
48 : // calling thread), false otherwise.
49 : bool Try();
50 :
51 : // @returns the recursion count of the lock.
52 E : size_t recursion() const { return recursion_; }
53 :
54 : protected:
55 : // The internal lock logic. Returns true if the lock is acquired, false
56 : // otherwise. If |wait| is true then this blocks until the lock is acquired.
57 : bool TryImpl(bool wait);
58 :
59 : // Ensures thread safety for this object.
60 : base::Lock lock_;
61 : // A condition variable that is signalled when the lock is freed. Under lock_.
62 : base::ConditionVariable lock_is_free_;
63 : // The ID of the thread holding the lock. This is zero if no thread holds the
64 : // lock. Under lock_.
65 : size_t thread_id_;
66 : // Holds the recursion depth. Under lock_.
67 : size_t recursion_;
68 :
69 : private:
70 : DISALLOW_COPY_AND_ASSIGN(RecursiveLock);
71 : };
72 :
73 : // A scoped lock helper for recursive locks.
74 : class AutoRecursiveLock {
75 : public:
76 E : explicit AutoRecursiveLock(RecursiveLock& recursive_lock)
77 : : recursive_lock_(recursive_lock) {
78 E : recursive_lock_.Acquire();
79 E : }
80 :
81 E : ~AutoRecursiveLock() {
82 E : recursive_lock_.Release();
83 E : }
84 :
85 : protected:
86 : RecursiveLock& recursive_lock_;
87 :
88 : private:
89 : DISALLOW_COPY_AND_ASSIGN(AutoRecursiveLock);
90 : };
91 :
92 : } // namespace common
93 :
94 : #endif // SYZYGY_COMMON_RECURSIVE_LOCK_H_
|