Merge pull request #211 from Montellese/jsonrpc_actor_thumb
[vuplus_xbmc] / xbmc / threads / CriticalSection.h
1 /*
2  *      Copyright (C) 2005-2011 Team XBMC
3  *      http://www.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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #pragma once
23
24 #include <boost/thread/recursive_mutex.hpp>
25
26 namespace XbmcThreads
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
50   {
51   protected:
52     L mutex;
53     unsigned int count;
54
55   public:
56     inline CountingLockable() : count(0) {}
57
58     // boost::thread Lockable concept
59     inline void lock() { mutex.lock(); count++; }
60     inline bool try_lock() { return mutex.try_lock() ? count++, true : false; }
61     inline void unlock() { count--; mutex.unlock(); }
62
63     /**
64      * This implements the "exitable" behavior mentioned above.
65      */
66     inline unsigned int exit() 
67     { 
68       // it's possibe we don't actually own the lock
69       // so we will try it.
70       unsigned int ret = 0;
71       if (try_lock())
72       {
73         ret = count - 1;  // The -1 is because we don't want 
74         //  to count the try_lock increment.
75         while (count > 0) // This will also unlock the try_lock.
76           unlock();
77       }
78
79       return ret; 
80     }
81
82     /**
83      * Restore a previous exit to the provided level.
84      */
85     inline void restore(unsigned int restoreCount)
86     {
87       for (unsigned int i = 0; i < restoreCount; i++) 
88         lock();
89     }
90
91     inline unsigned int getCount() { return count; }
92
93     inline L& getLockable() { return mutex; }
94   };
95 }
96
97 /**
98  * A CCriticalSection is a CountingLockable whose implementation is a boost
99  *  recursive_mutex.
100  *
101  * This is not a typedef because of a number of "class CCriticalSection;" 
102  *  forward declarations in the code that break when it's done that way.
103  */
104 class CCriticalSection : public XbmcThreads::CountingLockable<boost::recursive_mutex> {};
105