xref: /haiku/headers/private/kernel/util/AutoLock.h (revision 95bac3fda53a4cb21880712d7b43f8c21db32a2e)
1 /*
2  * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #ifndef KERNEL_UTIL_AUTO_LOCKER_H
7 #define KERNEL_UTIL_AUTO_LOCKER_H
8 
9 #include <lock.h>
10 
11 namespace BPrivate {
12 
13 // AutoLockerStandardLocking
14 template<typename Lockable>
15 class AutoLockerStandardLocking {
16 public:
17 	inline bool Lock(Lockable *lockable)
18 	{
19 		return lockable->Lock();
20 	}
21 
22 	inline void Unlock(Lockable *lockable)
23 	{
24 		lockable->Unlock();
25 	}
26 };
27 
28 // AutoLockerReadLocking
29 template<typename Lockable>
30 class AutoLockerReadLocking {
31 public:
32 	inline bool Lock(Lockable *lockable)
33 	{
34 		return lockable->ReadLock();
35 	}
36 
37 	inline void Unlock(Lockable *lockable)
38 	{
39 		lockable->ReadUnlock();
40 	}
41 };
42 
43 // AutoLockerWriteLocking
44 template<typename Lockable>
45 class AutoLockerWriteLocking {
46 public:
47 	inline bool Lock(Lockable *lockable)
48 	{
49 		return lockable->WriteLock();
50 	}
51 
52 	inline void Unlock(Lockable *lockable)
53 	{
54 		lockable->WriteUnlock();
55 	}
56 };
57 
58 // AutoLocker
59 template<typename Lockable,
60 		 typename Locking = AutoLockerStandardLocking<Lockable> >
61 class AutoLocker {
62 private:
63 	typedef AutoLocker<Lockable, Locking>	ThisClass;
64 public:
65 	inline AutoLocker(Lockable *lockable, bool alreadyLocked = false)
66 		: fLockable(lockable),
67 		  fLocked(fLockable && alreadyLocked)
68 	{
69 		if (!fLocked)
70 			_Lock();
71 	}
72 
73 	inline AutoLocker(Lockable &lockable, bool alreadyLocked = false)
74 		: fLockable(&lockable),
75 		  fLocked(fLockable && alreadyLocked)
76 	{
77 		if (!fLocked)
78 			_Lock();
79 	}
80 
81 	inline ~AutoLocker()
82 	{
83 		_Unlock();
84 	}
85 
86 	inline void SetTo(Lockable *lockable, bool alreadyLocked)
87 	{
88 		_Unlock();
89 		fLockable = lockable;
90 		fLocked = alreadyLocked;
91 		if (!fLocked)
92 			_Lock();
93 	}
94 
95 	inline void SetTo(Lockable &lockable, bool alreadyLocked)
96 	{
97 		SetTo(&lockable, alreadyLocked);
98 	}
99 
100 	inline void Unset()
101 	{
102 		_Unlock();
103 	}
104 
105 	inline void Unlock()
106 	{
107 		_Unlock();
108 	}
109 
110 	inline void Detach()
111 	{
112 		fLockable = NULL;
113 		fLocked = false;
114 	}
115 
116 	inline AutoLocker<Lockable, Locking> &operator=(Lockable *lockable)
117 	{
118 		SetTo(lockable);
119 		return *this;
120 	}
121 
122 	inline AutoLocker<Lockable, Locking> &operator=(Lockable &lockable)
123 	{
124 		SetTo(&lockable);
125 		return *this;
126 	}
127 
128 	inline bool IsLocked() const	{ return fLocked; }
129 
130 	inline operator bool() const	{ return fLocked; }
131 
132 private:
133 	inline void _Lock()
134 	{
135 		if (fLockable)
136 			fLocked = fLocking.Lock(fLockable);
137 	}
138 
139 	inline void _Unlock()
140 	{
141 		if (fLockable && fLocked) {
142 			fLocking.Unlock(fLockable);
143 			fLocked = false;
144 		}
145 	}
146 
147 private:
148 	Lockable	*fLockable;
149 	bool		fLocked;
150 	Locking		fLocking;
151 };
152 
153 
154 // #pragma mark -
155 // #pragma mark ----- instantiations -----
156 
157 // MutexLocking
158 class MutexLocking {
159 public:
160 	inline bool Lock(mutex *lockable)
161 	{
162 		mutex_lock(lockable);
163 		return true;
164 	}
165 
166 	inline void Unlock(mutex *lockable)
167 	{
168 		mutex_unlock(lockable);
169 	}
170 };
171 
172 // MutexLocker
173 typedef AutoLocker<mutex, MutexLocking> MutexLocker;
174 
175 // RecursiveLockLocking
176 class RecursiveLockLocking {
177 public:
178 	inline bool Lock(recursive_lock *lockable)
179 	{
180 		recursive_lock_lock(lockable);
181 		return true;
182 	}
183 
184 	inline void Unlock(recursive_lock *lockable)
185 	{
186 		recursive_lock_unlock(lockable);
187 	}
188 };
189 
190 // RecursiveLocker
191 typedef AutoLocker<recursive_lock, RecursiveLockLocking> RecursiveLocker;
192 
193 }	// namespace BPrivate
194 
195 using BPrivate::AutoLocker;
196 using BPrivate::MutexLocker;
197 using BPrivate::RecursiveLocker;
198 
199 #endif	// KERNEL_UTIL_AUTO_LOCKER_H
200