Merge pull request #3164 from koying/fixdroiddvdiso
[vuplus_xbmc] / xbmc / threads / Lockables.h
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #pragma once
22
23 #include "threads/Helpers.h"
24
25 namespace XbmcThreads
26 {
27
28   /**
29    * This template will take any implementation of the "Lockable" concept
30    * and allow it to be used as an "Exitable Lockable."
31    *
32    * Something that implements the "Lockable concept" simply means that 
33    * it has the three methods:
34    *
35    *   lock();
36    *   try_lock();
37    *   unlock();
38    *
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
41    * the state.
42    *
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).
46    *
47    * All xbmc code expects Lockables to be recursive.
48    */
49   template<class L> class CountingLockable : public NonCopyable
50   {
51     friend class ConditionVariable;
52   protected:
53     L mutex;
54     unsigned int count;
55
56   public:
57     inline CountingLockable() : count(0) {}
58
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(); }
63
64     /**
65      * This implements the "exitable" behavior mentioned above.
66      *
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.
72      */
73     inline unsigned int exit(unsigned int leave = 0) 
74     { 
75       // it's possibe we don't actually own the lock
76       // so we will try it.
77       unsigned int ret = 0;
78       if (try_lock())
79       {
80         if (leave < (count - 1))
81         {
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
86           // can modify it.
87           for (unsigned int i = 0; i < ret; i++)
88             unlock();
89         }
90         unlock(); // undo the try_lock before returning
91       }
92
93       return ret; 
94     }
95
96     /**
97      * Restore a previous exit to the provided level.
98      */
99     inline void restore(unsigned int restoreCount)
100     {
101       for (unsigned int i = 0; i < restoreCount; i++) 
102         lock();
103     }
104
105     /**
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.
110      *
111      * There really should be no need for the users of the threading library
112      *  to call this method.
113      */
114     inline L& get_underlying() { return mutex; }
115   };
116
117
118   /**
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.
121    */
122   template<typename L> class UniqueLock : public NonCopyable
123   {
124   protected:
125     L& mutex;
126     bool owns;
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(); }
130
131   public:
132
133     inline bool owns_lock() const { return owns; }
134
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; } }
139
140     /**
141      * See the note on the same method on CountingLockable
142      */
143     inline L& get_underlying() { return mutex; }
144   };
145
146   /**
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.
149    *
150    * Something that implements the "Shared Lockable" concept has all of the methods
151    * required by the Lockable concept and also:
152    *
153    * void lock_shared();
154    * bool try_lock_shared();
155    * void unlock_shared();
156    */
157   template<typename L> class SharedLock : public NonCopyable
158   {
159   protected:
160     L& mutex;
161     bool owns;
162     inline SharedLock(L& lockable) : mutex(lockable), owns(true) { mutex.lock_shared(); }
163     inline ~SharedLock() { if (owns) mutex.unlock_shared(); }
164
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; }
169
170     /**
171      * See the note on the same method on CountingLockable
172      */
173     inline L& get_underlying() { return mutex; }
174   };
175
176
177 }