Merge pull request #209 from jimfcarroll/remove-circ-deps
[vuplus_xbmc] / xbmc / threads / CriticalSection.h
1 //////////////////////////////////////////////////////////////////////
2 //
3 // CriticalSection.h: interface for the CCriticalSection class.
4 //
5 //////////////////////////////////////////////////////////////////////
6
7 #pragma once
8
9 /*
10  *      Copyright (C) 2005-2008 Team XBMC
11  *      http://www.xbmc.org
12  *
13  *  This Program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2, or (at your option)
16  *  any later version.
17  *
18  *  This Program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with XBMC; see the file COPYING.  If not, write to
25  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26  *  http://www.gnu.org/copyleft/gpl.html
27  *
28  */
29
30 #include <boost/thread/recursive_mutex.hpp>
31
32 /**
33  * Because there are several different Lockable schemes we use, this 
34  * template extends the boost behavior and adds some xbmc assumptions
35  * mainly that a CriticalSection (or SharedSection) is "exitable." 
36  *
37  * "Exitable" specifially means that, no matter how deep the recursion
38  * on the mutex/critical section, we can exit from it and then restore
39  * the state.
40  *
41  * This requires us to extend boost so that we can keep track of the
42  * number of locks that have been recursively acquired so that we can
43  * undo it, and then restore that (See class CSingleExit).
44  *
45  * This implements boost's "Lockable concept" which simply means that 
46  * it has the three methods:
47  *
48  *   lock();
49  *   try_lock();
50  *   unlock();
51  */
52 template<class L> class CountingLockable
53 {
54 protected:
55   L mutex;
56   unsigned int count;
57
58 public:
59   inline CountingLockable() : count(0) {}
60
61   // boost::thread Lockable concept
62   inline void lock() { mutex.lock(); count++; }
63   inline bool try_lock() { return mutex.try_lock() ? count++, true : false; }
64   inline void unlock() { count--; mutex.unlock(); }
65
66   /**
67    * This implements the "exitable" behavior mentioned above.
68    */
69   inline unsigned int exit() 
70   { 
71     // it's possibe we don't actually own the lock
72     // so we will try it.
73     unsigned int ret = 0;
74     if (try_lock())
75     {
76       ret = count - 1;  // The -1 is because we don't want 
77                         //  to count the try_lock increment.
78       while (count > 0) // This will also unlock the try_lock.
79         unlock();
80     }
81
82     return ret; 
83   }
84
85   /**
86    * Restore a previous exit to the provided level.
87    */
88   inline void restore(unsigned int restoreCount)
89   {
90     for (unsigned int i = 0; i < restoreCount; i++) 
91       lock();
92   }
93
94   inline unsigned int getCount() { return count; }
95
96   inline L& getLockable() { return mutex; }
97 };
98
99 /**
100  * A CCriticalSection is a CountingLockable whose implementation is a boost
101  *  recursive_mutex.
102  *
103  * This is not a typedef because of a number of "class CCriticalSection;" 
104  *  forward declarations in the code that break when it's done that way.
105  */
106 class CCriticalSection : public CountingLockable<boost::recursive_mutex> {};
107