2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 #include "threads/Helpers.h"
29 * This template will take any implementation of the "Lockable" concept
30 * and allow it to be used as an "Exitable Lockable."
32 * Something that implements the "Lockable concept" simply means that
33 * it has the three methods:
39 * "Exitable" specifially means that, no matter how deep the recursion
40 * on the mutex/critical section, we can exit from it and then restore
43 * This requires us to extend the Lockable so that we can keep track of the
44 * number of locks that have been recursively acquired so that we can
45 * undo it, and then restore that (See class CSingleExit).
47 * All xbmc code expects Lockables to be recursive.
49 template<class L> class CountingLockable : public NonCopyable
51 friend class ConditionVariable;
57 inline CountingLockable() : count(0) {}
59 // boost::thread Lockable concept
60 inline void lock() { mutex.lock(); count++; }
61 inline bool try_lock() { return mutex.try_lock() ? count++, true : false; }
62 inline void unlock() { count--; mutex.unlock(); }
65 * This implements the "exitable" behavior mentioned above.
67 * This can be used to ALMOST exit, but not quite, by passing
68 * the number of locks to leave. This is used in the windows
69 * ConditionVariable which requires that the lock be entered
70 * only once, and so it backs out ALMOST all the way, but
71 * leaves one still there.
73 inline unsigned int exit(unsigned int leave = 0)
75 // it's possibe we don't actually own the lock
80 if (leave < (count - 1))
82 ret = count - 1 - leave; // The -1 is because we don't want
83 // to count the try_lock increment.
84 // We must NOT compare "count" in this loop since
85 // as soon as the last unlock is called another thread
87 for (unsigned int i = 0; i < ret; i++)
90 unlock(); // undo the try_lock before returning
97 * Restore a previous exit to the provided level.
99 inline void restore(unsigned int restoreCount)
101 for (unsigned int i = 0; i < restoreCount; i++)
106 * Some implementations (see pthreads) require access to the underlying
107 * CCriticalSection, which is also implementation specific. This
108 * provides access to it through the same method on the guard classes
109 * UniqueLock, and SharedLock.
111 * There really should be no need for the users of the threading library
112 * to call this method.
114 inline L& get_underlying() { return mutex; }
119 * This template can be used to define the base implementation for any UniqueLock
120 * (such as CSingleLock) that uses a Lockable as its mutex/critical section.
122 template<typename L> class UniqueLock : public NonCopyable
127 inline UniqueLock(L& lockable) : mutex(lockable), owns(true) { mutex.lock(); }
128 inline UniqueLock(L& lockable, bool try_to_lock_discrim ) : mutex(lockable) { owns = mutex.try_lock(); }
129 inline ~UniqueLock() { if (owns) mutex.unlock(); }
133 inline bool owns_lock() const { return owns; }
135 //This also implements lockable
136 inline void lock() { mutex.lock(); owns=true; }
137 inline bool try_lock() { return (owns = mutex.try_lock()); }
138 inline void unlock() { if (owns) { mutex.unlock(); owns=false; } }
141 * See the note on the same method on CountingLockable
143 inline L& get_underlying() { return mutex; }
147 * This template can be used to define the base implementation for any SharedLock
148 * (such as CSharedLock) that uses a Shared Lockable as its mutex/critical section.
150 * Something that implements the "Shared Lockable" concept has all of the methods
151 * required by the Lockable concept and also:
153 * void lock_shared();
154 * bool try_lock_shared();
155 * void unlock_shared();
157 template<typename L> class SharedLock : public NonCopyable
162 inline SharedLock(L& lockable) : mutex(lockable), owns(true) { mutex.lock_shared(); }
163 inline ~SharedLock() { if (owns) mutex.unlock_shared(); }
165 inline bool owns_lock() const { return owns; }
166 inline void lock() { mutex.lock_shared(); owns = true; }
167 inline bool try_lock() { return (owns = mutex.try_lock_shared()); }
168 inline void unlock() { if (owns) mutex.unlock_shared(); owns = false; }
171 * See the note on the same method on CountingLockable
173 inline L& get_underlying() { return mutex; }